git-bash, как обрабатывать пробелы в именах файлов

1052
Thom

Я написал следующий скрипт для запуска под 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
slhck

Решение 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 ''in read).