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


Я запускаю 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
2017-12-19 21:20


Источник




Ответы:


Если вы хотите использовать 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

4
2017-12-19 21:24



хороший совет. Я не думаю, что MacOS использует инструменты GNU. @daveA, проверьте свою справочную страницу для поиска и xargs для параметров, которые позволяют отделять результаты с символом без пробелов. - glenn jackman
Варианты BSD find а также xargs включенные в OS X, поддерживают -print0 а также -0 соответственно. - slhck


Безусловно, самый безопасный и простой способ сделать это - использовать 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 опция будет запускать все, что вы даете ей по результатам поиска, заменяя {} с каждым найденным файлом (или каталогом). Итак, чтобы grep для конкретной строки, вы бы сделали:

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' {} +

2
2017-12-19 21:49



Вам нужно избегать или одинарной кавычки ; или +, В противном случае они будут потребляться оболочкой, а не find, - slhck
@slhck, по крайней мере, на bash и Linux, нет причин убегать +, это не имеет особого значения для оболочки, что является одной из причин, по которым я использовал это вместо ;, - terdon