Подтвердить что ты не робот

Есть ли эквивалент grep для переключателей find -print0 и xargs -0?

Я часто хочу писать такие команды (в zsh, если это необходимо):

find <somebasedirectory> | \
    grep stringinfilenamesIwant | \
    grep -v stringinfilesnamesIdont | \
    xargs dosomecommand

(или более сложные комбинации greps)

В последние годы find добавлен переключатель -print0, и xargs добавил -0, что позволяет обрабатывать файлы с пробелами в имени элегантным способом путем нумерации имен файлов вместо этого, что позволяет:

find <somebasedirectory> -print0 | xargs -0 dosomecommand

Однако grep (по крайней мере версия, которую я имею, GNU grep 2.10 на Ubuntu), похоже, не имеет эквивалента, чтобы потреблять и генерации строк с нулевым завершением; он имеет --null, но это только кажется связанным с использованием -l для вывода имен при поиске в файлах напрямую с помощью grep.

Есть ли эквивалентная опция или комбинация параметров, которые я могу использовать с grep? Альтернативно, есть простой и элегантный способ выразить свою команду команд просто используя find -regex или, возможно, Perl?

4b9b3361

Ответ 1

Использовать GNU Grep --null Флаг

В соответствии с документацией GNU Grep вы можете использовать Output Prefix Control для обработки символов ASCII NUL так же, как find и xargs.

-Z
--null
    Выведите нулевой байт (символ ASCII NUL) вместо символа, который обычно следует за именем файла. Например, 'grep -lZ выводит нулевой байт после каждого имени файла вместо обычной новой строки. Эта опция делает вывод однозначным даже при наличии имен файлов, содержащих необычные символы, такие как символы новой строки. Эта опция может использоваться с командами типа "find -print0", "perl -0", "sort -z" и "xargs -0" для обработки произвольных имен файлов, даже тех, которые содержат символы новой строки.

Использовать tr для GNU Coreutils

Как правильно указывает OP, этот флаг наиболее полезен при обработке имен файлов на входе или выходе. Чтобы фактически преобразовать вывод grep для использования символов NUL в качестве окончаний строки, вам нужно использовать инструмент, например sed или tr, для преобразования каждой строки вывода. Например:

find /etc/passwd -print0 |
    xargs -0 egrep -Z 'root|www' |
    tr "\n" "\0" |
    xargs -0 -n1

Этот конвейер будет использовать NUL для разделения имен файлов из find, а затем преобразовать символы новой строки в NUL в строках, возвращаемых egrep. Это передаст строки с нулевым завершением следующей команде в конвейере, которая в этом случае будет просто xargs, возвращая результат обратно в обычные строки, но это может быть все, что вы хотите.

Ответ 2

Поскольку вы уже используете GNU find, вместо этих grep вы можете использовать свои возможности для соответствия шаблону регулярного выражения, например:

find <somebasedirectory> -regex ".*stringinfilenamesIwant.*" ! -regex ".*stringinfilesnamesIdont.*" -exec dosomecommand {} + 

Ответ 3

Вместо использования трубы вы можете использовать find -exec с терминатором +. Чтобы объединить несколько команд вместе, вы можете создать оболочку в -exec.

find ./ -type f -exec bash -c 'grep "[email protected]" | grep -v something | xargs dosomething' -- {} +

Ответ 4

В новейшей версии источника GNU grep теперь можно использовать -z/--null для разделения вывода пустыми символами, тогда как ранее он работал только с -l:

http://git.savannah.gnu.org/cgit/grep.git/commit/?id=cce2fd5520bba35cf9b264de2f1b6131304f19d2

Это означает, что ваша проблема решается автоматически при использовании самой новой версии.

Ответ 5

Использование

find <somebasedirectory> -print0 | \
 grep -z stringinfilenamesIwant | \
 grep -zv stringinfilesnamesIdont | \
 xargs -0 dosomecommand

Однако шаблон не может содержать новую строку, см. отчет об ошибках.

Ответ 6

find <somebasedirectory> -print0 | xargs -0 -I % grep something '%'