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

Я использую Mac 10.7.5. В терминале я буду использовать эту команду для поиска файлов со строками

find src/main -name "*" | xargs grep -i 'mystring'

Однако, когда файлы содержат пробелы, я получу результаты, как

grep: images/mystuff/essential-questions-selected-arrow-ela: No such file or directory
grep: 5.24.38: No such file or directory
grep: PM.png: No such file or directory

Фактический файл в приведенном выше примере - "essential-questions-selected-arrow-ela 5.24.38 PM.png". Как мне успешно выполнить указанную выше команду, даже если в искомых файлах есть пробелы?

2 ответа

Решение

Если вы хотите использовать find вывод в xargs рекомендуемый способ - это использовать NUL символы для разделения каждого имени файла:

find src/main -name "*" -print0 | xargs -0 grep -i 'mystring'

Причина этого заключается в том, что оболочка (и xargs в частности) обычно разделяет аргументы (или ввод в случае xargs) на основе пробелов, то есть пробелов, табуляции и новых строк. Как только вы используете -0, xargs будет читать каждое поле, разделенное NUL, который является то, что find -print0 выходы.

Это будет работать в GNU find а также xargs а также версии, включенные в OS X. Другие версии могут не иметь опций, так как они не требуются в POSIX.


Но опять же, это не является действительно необходимым. "*" Шаблон имени распространяется на все возможные имена. grep может рекурсировать самостоятельно, поэтому все, что нужно, это:

grep -ri 'mystring' src/main

В Bash 4 (по умолчанию не поставляется с OS X) вы также можете выполнять рекурсивное сглаживание, например, над всеми .txt файлы, используя globstar вариант:

shopt -s globstar
grep -i 'mystring' **/*.txt

Безусловно, самый безопасный и простой способ сделать это - использовать find -exec вариант. От man find:

-exec utility [argument ...] ;
     True if the program named utility returns a zero value as its exit status.
     Optional arguments may be passed to the utility.  The expression must be 
     terminated by a semicolon (``;'').  If you invoke find from a shell you 
     may need to quote the semicolon if the shell would otherwise treat it as a 
     control operator.  If the string ``{}'' appears anywhere in the utility 
     name or the arguments it is replaced by the pathname of the current file.  
     Utility will be executed from the directory from which find was executed.  
     Utility and arguments are not subject to the further expansion of shell 
     patterns and constructs.

-exec utility [argument ...] {} +
     Same as -exec, except that ``{}'' is replaced with as many pathnames as 
     possible for each invo-cation invocationcation of utility. This behaviour 
     is similar to that of xargs(1).

Другими словами -exec опция запустит все что вы дадите по результатам поиска, заменив {} с каждым найденным файлом (или каталогом). Итак, чтобы выполнить поиск определенной строки, вы должны сделать:

find src/main -name "*" -exec grep -i 'mystring' {} +

Это, однако, также найдет каталоги и выдаст ошибку. Имейте в виду, что он будет работать, когда вы попытаетесь запустить его в каталоге, у вас возникла бы та же проблема с использованием xargs, То, что вы на самом деле пытаетесь сделать здесь, это найти все файлы и только файлы. В этом случае -name '*' не нужен, так как find src/main точно так же, как find src/main -name "*", Таким образом, вместо того, чтобы использовать это, укажите, что вы хотите только найти файлы:

find src/main -type f -exec grep -i 'mystring' {} +
Другие вопросы по тегам