1

Я написал следующий скрипт для запуска под git-bash под Windows 7:

#!/usr/bin/env sh
for logfile in `find -name "*.log" -o -name "*.err" -o -name "*.out"`
do
    echo $logfile
    grep "api/" "$logfile"
done

Проблема в том, что grep задыхается, когда в имени файла есть пробел. Я думал, что двойные кавычки должны позаботиться об этом, но это не сотрудничество.

Идеи?

Кроме того, вы можете сказать, что я пытаюсь сделать. Любые другие предложения будут приветствоваться.

1 ответ1

3

Решение 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 ) ,

Всё ещё ищете ответ? Посмотрите другие вопросы с метками .