Решение 1
Наиболее близким решением является использование команды find
с -print0
и чтение вывода с помощью while read …
:
find -name "*.log" -o -name "*.err" -o -name "*.out" -type f -print0 | while IFS= read -r -d '' logfile; do
...
Продолжайте использовать "$logfile"
с кавычками, как всегда, когда используете переменные.
Решение 2
Другим решением было бы вообще не использовать find
и просто запускать grep
для нескольких файлов:
shopt -s nullglob
shopt -s globstar
grep "api/" **/*.log **/*.err **/*.out
Здесь globstar
позволяет рекурсивное сопоставление каталогов с **
. Вы должны установить nullglob
для предотвращения ошибок, если одно из этих расширений файлов не существует.
Это работает только для ограниченного набора файлов, так как вы можете достичь максимальной длины аргументов командной строки.
Почему происходит ошибка?
Вы никогда не должны запускаться for
на выходе find
(или ls
, или любой другой функции, которая выводит имена файлов с пробелами). Прочитайте эту статью для получения дополнительной информации о том, почему это проблема и что можно сделать, чтобы ее решить.
Короче говоря, Bash разделяет аргументы по пробелам. Представьте, что у вас есть три файла:a
, foo bar
и b
, тогда строка будет выглядеть так:
for logfile in a foo bar b; do
Очевидно, что Bash установит logfile
в a
, foo
, bar
и b
, что не то, что вы хотели. Если бы вы могли вручную указать входные данные для for
, вы бы заключили эти имена в кавычки, чтобы решить проблему.
Для того, чтобы сделать это автоматически, решение состоит в том, чтобы разграничить эти имена файлов символом NUL
(что и делает опция -print0
), а затем снова разделить вывод на основе этого символа NUL
(что и делает -d ''
в read
) ,