Как обрабатывать пробелы в именах файлов в Git Bash

Как обрабатывать пробелы в именах файлов в Git Bash

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

Наиболее близким решением является использование findwith -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).

Связанный контент