Команда Grep для поиска файлов, содержащих текстовую строку, и перемещения их

Я могу найти файлы в папке, содержащей определенную текстовую строку, используя эту команду:

grep -lir 'string' ~/directory/* 

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

Как всегда, остерегайтесь grep -r . -r не является стандартным вариантом, и в некоторых реализациях, таких как все, но очень последние версии GNU grep , он следует за символическими ссылками при смене дерева каталогов, который обычно не является тем, что вы хотите, и может иметь серьезные последствия, если, например, есть символическая ссылка на «/» где-нибудь в дереве каталогов.

В философии Unix вы используете команду для поиска каталогов для файлов, а другую для просмотра ее содержимого.

Используя инструменты GNU, я бы сделал:

 xargs -r0 --arg-file <(find . -type f -exec grep -lZi string {} + ) mv -i --target-directory /dest/dir 

Но даже тогда остерегайтесь условий гонки и возможных проблем с безопасностью, если вы запускаете ее как один пользователь в каталоге, который может записать другой пользователь.

Используйте xargs в согласии с третьим синтаксисом mv [OPTION]... -t DIRECTORY SOURCE... : mv [OPTION]... -t DIRECTORY SOURCE...

 grep -lir 'string' ~/directory/* | xargs mv -t DEST 

Будьте осторожны с файлами, содержащими специальные символы (пробелы, кавычки). Если это ваш случай, фильтрация списка с помощью sed (добавление котировок вокруг имен файлов с помощью s/^/'/;s/$/'/ ) может помочь, но вы должны быть уверены, что эти кавычки не будут отображаться в имена файлов. GNU grep имеет параметр -Z / --null для NUL-завершения имен файлов.

Альтернативой третьему синтаксису для mv является использование xargs с строкой-заполнителем ( -I ).

Другим вариантом является подстановка команды – $( ) или обратные выходы `` (в bash), как указано в ответе ire_and_curses.

Если имена ваших файлов не содержат каких-либо специальных символов (пробелы или \[*? ), Используйте команду substitution :

 mv `grep -lir 'string' ~/directory/*` destination/ 

Использование параллельной GNU :

 grep -i -Z -r -l 'string' . | parallel 'mv {} destination/{}' 

ht / @ lin-dong для его первоначального ответа с xargs.

Используя только указанные функции POSIX и не делая никаких предположений о именах файлов:

 find ~/directory -type f -exec grep -qiF 'string' {} \; -exec mv {} /path/to/dest \; 

Заметки:

Вы сказали «строка» не «шаблон», поэтому опция -F (фиксированный поиск строк) grep представляется подходящей.

Если ваш целевой каталог находится где-нибудь внутри вашего каталога поиска, у вас могут быть некоторые неприятные условия гонки.

Спецификации POSIX для grep

Спецификации POSIX для find