Пробелы в именах путей, приводящие к проблемам с Find in Bash. Любой * простой * обходной путь? - PullRequest
3 голосов
/ 10 октября 2010

Можно ли как-нибудь изменить следующую строку, чтобы у меня не возникало проблем, если в них есть файлы / папки с пробелами?

files=`find ~/$folder -name "*@*" -type f`

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

Спасибо

РЕДАКТИРОВАТЬ: Здесьэто код более подробно:

abc=( $(find "$pasta" -name "$ficheiro_original@*" -type f) )
abc_length=${#abc[@]}

Ответы [ 5 ]

10 голосов
/ 10 октября 2010

Если вы не используете эти имена файлов позже в своем скрипте, просто итерируйте их и обрабатывайте на лету.

find ~/$folder -name "*@*" -type f | while read -r FILE
do
  echo "do you stuff"
done

В противном случае вы можете установить IFS

IFS=$'\n'
files=$(find ~/$folder -name "*@*" -type f)

Обновить:

$ IFS=$'\n'
$ a=($(find . -type f ))
$ echo ${#a[@]}
14
2 голосов
/ 10 октября 2010

Вам придется внести некоторые изменения, но для работы с произвольными именами подумайте об использовании опции поиска GNU -print0 и т. Д.

find ~/$folder -name "*@*" -type f -print0 |
while read -d '^@' file
do
    echo "<<$file>>"
done

(где отдельный байт, представленный как '^@', фактически является NSC ASCII ('\ 0'; введите с помощью Control-V Control-Shift - @ ).

find ~/$folder -name "*@*" -type f -print0 |
while read -d '' file
do
    echo "<<$file>>"
done

Пустая строка для разделителя означает «использовать нулевой байт, ASCII NUL, в качестве разделителя» и подходит для анализа вывода «find ... -print0». (Спасибо Деннис Уильямсон для подсказки.)

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

(Учитывая ответ на комментарий, о котором нужно беспокоиться только о пробелах, это может быть излишним, хотя использование read для обработки строк с именами является ключевой частью операции, а использование массива, вероятно, сделает жизнь проще.)

2 голосов
/ 10 октября 2010

Если вам нужен список файлов, в именах которых могут быть пробелы, вы должны хранить их как массив, а не как строку.Создайте массив с чем-то вроде этого:

saveIFS="$IFS"; IFS=$'\n'; files=( $(find ~/"$folder" -name "*@*" -type f) ); IFS="$saveIFS"

, и затем вам придется изменить оставшуюся часть скрипта, чтобы использовать файлы в качестве массива, а не строки, и он (и другие имена файлов) должен всегдабыть в двойных кавычках, чтобы избежать ошибочных пробелов в качестве разделителей.Например, в любом месте, где вы сейчас используете $files, замените его на "${files[@]}"

ls "${files[@]}"
for f in "${files[@]}"; do
    ls "$f"
done
echo "found ${#files[@]} files" 
1 голос
/ 10 октября 2010

Чтобы прочитать имена файлов с пробелами в переменную массива Bash, вы также можете использовать встроенную команду read:

printf '%q\n' "$IFS"

IFS=$'\n' read -r -d "" -a abc <<< "$(find ~/$folder -name "*@*" -type f)"
IFS=$'\n' read -r -d "" -a abc < <(find ~/$folder -name "*@*" -type f)  # alternative

abc_length=${#abc[@]}

for ((i=1; i <= ${#abc[@]}; i++)); do echo "$i:  ${abc[i-1]}"; done

printf '%q\n' "$IFS"

Обратите внимание, что область действия вновь установленной переменной IFS ограничена выполнением команды чтения (которая оставляет исходную переменную IFS без изменений).

1 голос
/ 10 октября 2010

Вот еще один способ обойти без изменения остальной части кода:

# files=($(find))
eval "files=($(find -printf '"%h/%f" '))"

for f in "${files[@]}"; do
  echo "$f"
done

Это грязно и не будет работать для имени файла со специальными символами, например ".Он использует eval для оценки строки массива Bash и -printf из find для формирования этой строки.

Я лично предпочитаю изменить $IFS, просто к вашему сведению.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...