Nano Hash - криптовалюты, майнинг, программирование

выполнить операцию для *каждого* элемента, указанного grep

Как я могу выполнить операцию для каждого элемента, указанного grep отдельно?

Фон:

Я использую grep для вывода списка всех файлов, содержащих определенный шаблон:

grep -l '<pattern>' directory/*.extension1

Я хочу удалить все перечисленные файлы, а также все файлы с таким же именем, но другим расширением: .extension2.

Я пытался использовать канал, но, похоже, он принимает вывод grep в целом.

В find есть опция -exec, а в grep ничего подобного нет.

13.03.2012

Ответы:


1

Если я понимаю вашу спецификацию, вы хотите:

grep --null -l '<pattern>' directory/*.extension1 | \
    xargs -n 1 -0 -I{} bash -c 'rm "$1" "${1%.*}.extension2"' -- {}

По сути, это то же самое, что описывает комментарий @triplee, за исключением того, что он безопасен для новой строки.

Что тут происходит?

grep с --null вернет вывод, разделенный нулями вместо новой строки. Поскольку в именах файлов могут быть новые строки, разделители с новой строкой делают невозможным безопасный анализ вывода grep, но null не является допустимым символом в имени файла и, таким образом, является хорошим разделителем.

xargs возьмет поток элементов, разделенных новой строкой, и выполнит заданную команду, передав как можно больше этих элементов (по одному на каждый параметр) заданной команде (или echo, если команда не указана). Таким образом, если вы сказали:

printf 'one\ntwo three \nfour\n' | xargs echo

xargs выполнит echo one 'two three' four. Это небезопасно для имен файлов, потому что, опять же, имена файлов могут содержать встроенные символы новой строки.

Переключение -0 на xargs изменяет поиск разделителя новой строки на нулевой разделитель. Это позволяет ему соответствовать выходным данным, полученным от grep --null, и делает его безопасным для обработки списка имен файлов.

Обычно xargs просто добавляет ввод в конец команды. Переключатель -I на xargs изменяет это, чтобы заменить указанную строку замены вводом. Чтобы получить представление, проведите этот эксперимент:

printf 'one\ntwo three \nfour\n' | xargs -I{} echo foo {} bar

Обратите внимание на отличие от более ранней команды printf | xargs.

В случае моего решения я выполняю команду bash, которой я передаю -c. Переключатель -c заставляет bash выполнять команды в следующем аргументе (и затем завершать работу) вместо запуска интерактивной оболочки. Следующий блок 'rm "$1" "${1%.*}.extension2"' является первым аргументом -c и является сценарием, который будет выполняться bash. Любые аргументы, следующие за аргументом сценария до -c, назначаются в качестве аргументов сценария. Это, если бы я сказал:

bash -c 'echo $0' "Hello, world"

Тогда Hello, world будет присвоено $0 (первый аргумент скрипта) и внутри скрипта я смогу echo вернуть его обратно.

Поскольку $0 обычно зарезервировано для имени скрипта, я передаю фиктивное значение (в данном случае --) в качестве первого аргумента, а затем вместо второго аргумента пишу {} — строку замены, которую я указал для xargs. Это будет заменено на xargs с каждым именем файла, проанализированным из вывода grep перед выполнением bash.

Сценарий мини-оболочки может показаться сложным, но он довольно тривиален. Во-первых, весь сценарий заключен в одинарные кавычки, чтобы вызывающая оболочка не могла его интерпретировать. Внутри скрипта я вызываю rm и передаю ему два имени файла для удаления: аргумент $1, который был именем файла, переданным при подстановке строки замены выше, и ${1%.*}.extension2. Последнее является подстановкой параметра в переменной $1. Важная часть - %.*, которая говорит

  • % Найдите соответствие с конца переменной и удалите самую короткую строку, соответствующую шаблону.
  • .* Образец представляет собой один период, за которым следует что-либо.

Это эффективно удаляет расширение, если таковое имеется, из имени файла. Вы сами можете наблюдать эффект:

foo='my file.txt'
bar='this.is.a.file.txt'
baz='no extension'
printf '%s\n'"${foo%.*}" "${bar%.*}" "${baz%.*}"

Поскольку расширение было удалено, я присоединяю желаемое альтернативное расширение .extension2 к удаленному имени файла, чтобы получить альтернативное имя файла.

13.03.2012
  • это выглядит хорошо, но не могли бы вы немного объяснить эти команды? Я тоже хочу кое-что узнать :) 14.03.2012

  • 2

    Если это делает то, что вы хотите, направьте вывод через /bin/sh.

    grep -l 'RE' folder/*.ext1 | sed 's/\(.*\).ext1/rm "&" "\1.ext2"/'
    

    Или, если sed вызывает у вас зуд:

    grep -l 'RE' folder/*.ext1 | while read file; do
      echo rm "$file" "${file%.ext1}.ext2"
    done
    

    Удалите echo, если вывод похож на команды, которые вы хотите запустить.

    Но вы можете сделать это и с find:

    find /path/to/start -name \*.ext1 -exec grep -q 'RE' {} \; -print | ...
    

    где ... — это либо сценарий sed, либо три строки от while до done.

    Идея здесь в том, что find будет... ну, "находить" вещи на основе квалификаторов, которые вы ему даете, а именно, что вещи соответствуют файлу glob "*.ext", И что результат "exec" успешен . -q указывает grep искать RE в {} (файл, предоставленный find) и выйти с ИСТИНА или ЛОЖЬ, не генерируя никаких собственных выходных данных.

    Единственная реальная разница между выполнением этого в find и с помощью grep заключается в том, что вы можете использовать потрясающую коллекцию условий find, чтобы при необходимости еще больше сузить поиск. man find для получения подробной информации. По умолчанию find будет рекурсивно обращаться к подкаталогам.

    13.03.2012

    3

    Вы можете передать список в xargs:

    grep -l '<pattern>' directory/*.extension1 | xargs rm
    

    Что касается второго набора файлов с другим расширением, я бы сделал это (как обычно, используйте xargs echo rm при тестировании для пробного прогона; я не проверял, это может работать некорректно с именами файлов с пробелами в них):

    filelist=$(grep -l '<pattern>' directory/*.extension1)
    echo $filelist | xargs rm
    echo ${filelist//.extension1/.extension2} | xargs rm
    
    13.03.2012
  • Если у вас нет имен файлов с символами новой строки, вы можете сделать что-то вроде 'grep -l 'pattern' directory/*.extension1 | sed 'p;s/\.extension1$/.extension2/' | xargs rm` 13.03.2012
  • @tripleee: согласен, так, наверное, лучше! Я не думал об этом. 13.03.2012
  • Я был бы очень осторожен с повторением расширений без кавычек и переходом к xargs rm - есть вероятность, что вы что-то неожиданно взорвете. 13.03.2012

  • 4

    Передайте результат в xargs, это позволит вам запускать команду для каждого совпадения.

    13.03.2012
    Новые материалы

    Кластеризация: более глубокий взгляд
    Кластеризация — это метод обучения без учителя, в котором мы пытаемся найти группы в наборе данных на основе некоторых известных или неизвестных свойств, которые могут существовать. Независимо от..

    Как написать эффективное резюме
    Предложения по дизайну и макету, чтобы представить себя профессионально Вам не позвонили на собеседование после того, как вы несколько раз подали заявку на работу своей мечты? У вас может..

    Частный метод Python: улучшение инкапсуляции и безопасности
    Введение Python — универсальный и мощный язык программирования, известный своей простотой и удобством использования. Одной из ключевых особенностей, отличающих Python от других языков, является..

    Как я автоматизирую тестирование с помощью Jest
    Шутка для победы, когда дело касается автоматизации тестирования Одной очень важной частью разработки программного обеспечения является автоматизация тестирования, поскольку она создает..

    Работа с векторными символическими архитектурами, часть 4 (искусственный интеллект)
    Hyperseed: неконтролируемое обучение с векторными символическими архитектурами (arXiv) Автор: Евгений Осипов , Сачин Кахавала , Диланта Хапутантри , Тимал Кемпития , Дасвин Де Сильва ,..

    Понимание расстояния Вассерштейна: мощная метрика в машинном обучении
    В обширной области машинного обучения часто возникает необходимость сравнивать и измерять различия между распределениями вероятностей. Традиционные метрики расстояния, такие как евклидово..

    Обеспечение масштабируемости LLM: облачный анализ с помощью AWS Fargate и Copilot
    В динамичной области искусственного интеллекта все большее распространение получают модели больших языков (LLM). Они жизненно важны для различных приложений, таких как интеллектуальные..