6

Я пытаюсь отобразить все файлы в /foo , сохраняя пробелы в перечисленных каталогах. В настоящее время каталог с именем "bar1 bar2" будет отображаться как /path/to/foo/bar1/ then /bar2 затем file.txt все в новых строках. Мне нужно это echo /path/to/foo/bar1 bar2/file.txt или /path/to/foo/bar1\ bar2/file.txt .

for file in $(find /path/to/foo/ -type f); do
  if [[ ... ]]; then
    echo "${file}"
  fi
done

Также попробовал:

for file in $(find /path/to/foo/ -type f | sed 's/ /\ /g'); do
  if [[ ... ]]; then
    echo "${file}"
    echo "$file" # variations i've tried
    echo $file   # variations i've tried
    echo ${file}
    otherCommand "${file}"
  fi
done

1 ответ1

14

Проблема не в $file , а в том, что вы используете $(find…) .

И регулярные переменные, и подстановки процесса $(…) подвергаются точно одинаковому типу расщепления слов. Если вы поставите $(find…) в двойные кавычки, вы получите одно слово со всем выводом. Если вы этого не сделаете, он будет разбит на любые пустые места - не только на новые строки или какие-то другие магические границы, которые вы, вероятно, ожидали.

Важной частью вышесказанного является то, что обратные слэши не обрабатываются при расширении переменной. Это просто разделено на пробелы и все.

(Другими словами, цитирование $file не помогло, потому что оно никогда не имело правильного значения в первую очередь!)

Если вы хотите обрабатывать все файлы рекурсивно, ваши варианты:

  1. Прочитать вывод из find другим способом:

    find … -print | while read -r file; do
        echo "Got $file"
    done
    

    (Примечание стороны: имена файлов могут технически включать в себя новые строки, так что вы можете захотеть , чтобы защититься от этого, так же редки , как это:

    find … -print0 | while read -r -d "" file; do
        echo "Got $file"
    done
    
  2. Для небольшого количества файлов используйте расширенные символы подстановки bash:

    shopt -s globstar
    for file in /path/to/foo/**; do
        echo "Got $file"
    done
    

С большими каталогами, преимущество find | while read означает, что он транслируется - ваш скрипт будет обрабатывать результаты по мере их поступления. Между тем, и $(find) и подстановочные знаки должны сначала собирать все в память, а только потом возвращать (возможно, массивные) результаты.

С другой стороны, использование трубы влияет на весь во while цикла ( а не только команда read так что если вы хотите запустить что - нибудь , что хочет читать ввод с клавиатуры, вам придется вручную предоставить его с оригинальным стандартного ввода, например , vim "$file" < /dev/tty .

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