У меня есть сценарий, который ищет все файлы в нескольких подпапках и архивах к 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
В дополнение к правильному цитированию вы можете указать 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.
find . <find arguments> -print0 | xargs -0 grep <pattern>
Попробуйте процитировать цикл for
следующим образом:
for FILE in "`find . -type f -name '*.*'`" # note the quotation marks
Без кавычек bash плохо обрабатывает пробелы и переводы строк (\n
) ...
Также попробуйте установить
IFS=\n'
Это работает и проще:
find . -name '<pattern>' | while read LINE; do echo "$LINE" ; done
Благодарим Рупу ( https://github.com/rupa/z ) за этот ответ.
Я сделал что-то подобное, чтобы найти файлы, которые могут содержать пробелы.
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
Работает как шарм:)
Использование 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
, чтобы избежать включения бита ./
в архив.
Большинство ответов здесь прерываются, если в имени файла есть символ новой строки. Я использую 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
Думаю, вам лучше использовать опцию find
-exec.
find . -type f -name '*.*' -exec tar -cpf archive.tar {} +
Find затем выполняет команду, используя системный вызов, так что пробелы и символы новой строки сохраняются (скорее, это конвейер, который потребует цитирования специальных символов). Обратите внимание, что tar -c работает независимо от того, существует архив или нет, и что (по крайней мере с bash) ни {}, ни + не нужно заключать в кавычки.
Как предложил 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.