Имена файлов с пробелами, повреждающимися для цикла, найдите команду

У меня есть сценарий, который ищет все файлы в нескольких подпапках и архивах к tar. Мой сценарий

for FILE in `find . -type f  -name '*.*'`
  do
if [[ ! -f archive.tar ]]; then

  tar -cpf archive.tar $FILE
else 
  tar -upf archive.tar $FILE 
fi
done

Команда находки дает мне следующий вывод

find . -type f  -iname '*.*'
./F1/F1-2013-03-19 160413.csv
./F1/F1-2013-03-19 164411.csv
./F1-FAILED/F2/F1-2013-03-19 154412.csv
./F1-FAILED/F3/F1-2011-10-02 212910.csv
./F1-ARCHIVE/F1-2012-06-30 004408.csv
./F1-ARCHIVE/F1-2012-05-08 190408.csv

Но Файловая переменная только хранит первую часть пути./F1/F1-2013-03-19 и затем следующую часть 160413.csv.

Я пытался использовать read с некоторое время циклом,

while read `find . -type f  -iname '*.*'`;   do ls $REPLY; done

но я получаю следующую ошибку

bash: read: `./F1/F1-2013-03-19': not a valid identifier

Кто-либо может предложить альтернативный путь?

Обновление

Как предложено в ответах ниже я обновил сценарии

#!/bin/bash

INPUT_DIR=/usr/local/F1
cd $INPUT_DIR
for FILE in "$(find  . -type f -iname '*.*')"
do
archive=archive.tar

        if [ -f $archive ]; then
        tar uvf $archive "$FILE"
        else
        tar -cvf $archive "$FILE"
        fi
done

Вывод, который я получаю,

./test.sh
tar: ./F1/F1-2013-03-19 160413.csv\n./F1/F1-2013-03-19 164411.csv\n./F1/F1-2013-03-19 153413.csv\n./F1/F1-2013-03-19 154412.csv\n./F1/F1-2012-09-10 113409.csv\n./F1/F1-2013-03-19 152411.csv\n./.tar\n./F1-FAILED/F3/F1-2013-03-19 154412.csv\n./F1-FAILED/F3/F1-2013-03-19 170411.csv\n./F1-FAILED/F3/F1-2012-09-10 113409.csv\n./F1-FAILED/F2/F1-2011-10-03 113911.csv\n./F1-FAILED/F2/F1-2011-10-02 165908.csv\n./F1-FAILED/F2/F1-2011-10-02 212910.csv\n./F1-ARCHIVE/F1-2012-06-30 004408.csv\n./F1-ARCHIVE/F1-2011-08-17 133905.csv\n./F1-ARCHIVE/F1-2012-10-21 154410.csv\n./F1-ARCHIVE/F1-2012-05-08 190408.csv: Cannot stat: No such file or directory
tar: Exiting with failure status due to previous errors
33
задан 10 September 2013 в 14:42

9 ответов

В дополнение к правильному цитированию вы можете указать find использовать разделитель NULL, а затем прочитать и обработать результаты в цикле while

while read -rd  

Это должно обрабатывать любые имена файлов, которые POSIX-совместимый - см. man find

   -print0
          True; print the full file name on the standard output, followed by a null character (instead of the newline character that  -print  uses).   This  allows  file
          names that contain newlines or other types of white space to be correctly interpreted by programs that process the find output.  This option corresponds to the
          -0 option of xargs.
\0' file; do something with "$file" done < <(find . -type f -name '*.*' -print0)

Это должно обрабатывать любые имена файлов, которые POSIX-совместимый - см. man find

   -print0
          True; print the full file name on the standard output, followed by a null character (instead of the newline character that  -print  uses).   This  allows  file
          names that contain newlines or other types of white space to be correctly interpreted by programs that process the find output.  This option corresponds to the
          -0 option of xargs.
0
ответ дан 10 September 2013 в 14:42
find . <find arguments> -print0 | xargs -0 grep <pattern>
0
ответ дан 10 September 2013 в 14:42

Попробуйте процитировать цикл for следующим образом:

for FILE in "`find . -type f  -name '*.*'`"   # note the quotation marks

Без кавычек bash плохо обрабатывает пробелы и переводы строк (\n) ...

Также попробуйте установить

IFS=\n'
0
ответ дан 10 September 2013 в 14:42

Это работает и проще:

find . -name '<pattern>' | while read LINE; do echo "$LINE" ; done

Благодарим Рупу ( https://github.com/rupa/z ) за этот ответ.

0
ответ дан 10 September 2013 в 14:42

Я сделал что-то подобное, чтобы найти файлы, которые могут содержать пробелы.

IFS= 

Работает как шарм:)

\n' for FILE in `/usr/bin/find $DST/shared -name *.nsf | grep -v bookmark.nsf | grep -v names.nsf`; do file $FILE | tee -a $LOG done

Работает как шарм:)

0
ответ дан 10 September 2013 в 14:42

Использование for с find является неправильным подходом, см., Например, это описание о банке червей, которую вы открываете.

Рекомендуемый подход заключается в использовании find, while и read, как описано здесь . Ниже приведен пример, который должен работать для вас:

find . -type f -name '*.*' -print0 | 
while IFS= read -r -d '' file; do
    printf '%s\n' "$file"
done

Таким образом, вы разделяете имена файлов с нулевыми (\0) символами, это означает, что изменение в пространстве и другие специальные символы не вызовут проблем. 1117]

Чтобы обновить архив с помощью файлов, которые find находится, вы можете передать его выходные данные непосредственно в tar:

find . -type f -name '*.*' -printf '%p\0' | 
tar --null -uf archive.tar -T -

Обратите внимание, что вам не нужно различать, если архив существует или нет, tar будет обращаться с этим разумно. Также обратите внимание на использование здесь -printf, чтобы избежать включения бита ./ в архив.

0
ответ дан 10 September 2013 в 14:42

Большинство ответов здесь прерываются, если в имени файла есть символ новой строки. Я использую bash более 15 лет, но только в интерактивном режиме.

В Python вы можете использовать os.walk (): http://docs.python.org/2/library/os.html#os.walk

И tarfile модуль: http://docs.python.org/2/library/tarfile.html#tar-examples

0
ответ дан 10 September 2013 в 14:42

Думаю, вам лучше использовать опцию find -exec.

find . -type f -name '*.*' -exec tar -cpf archive.tar {} +

Find затем выполняет команду, используя системный вызов, так что пробелы и символы новой строки сохраняются (скорее, это конвейер, который потребует цитирования специальных символов). Обратите внимание, что tar -c работает независимо от того, существует архив или нет, и что (по крайней мере с bash) ни {}, ни + не нужно заключать в кавычки.

0
ответ дан 10 September 2013 в 14:42

Как предложил minerz029, вам нужно процитировать расширение команды find. Вам также нужно процитировать все замены $FILE в вашем цикле.

for FILE in "$(find . -type f  -name '*.*')"
do
    if [ ! -f archive.tar ]; then
        tar -cpf archive.tar "$FILE"
    else 
        tar -upf archive.tar "$FILE" 
    fi
done

Обратите внимание, что синтаксис $() должен быть предпочтительнее использования обратных тиков; см. этот U & amp; L вопрос . Я также удалил ключевое слово [[ и заменил его командой [, потому что это POSIX.

0
ответ дан 10 September 2013 в 14:42

Другие вопросы по тегам:

Похожие вопросы: