У меня есть скрипт, который ищет все файлы в нескольких подпапках и архивах в 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 дает мне следующий вывод
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
Но переменная FILE хранит только первую часть пути ./F1/F1-2013-03-19, а затем следующую часть 160413.csv .
Я пытался использовать read
с циклом while,
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
IFS=$'\n'
перед циклом `for, чтобы он разбирался по каждой строкеОтветы:
Использование
for
сfind
- неправильный подход, посмотрите, например, это описание о черве, которое вы открываете.Рекомендуемый подход заключается в использовании
find
,while
иread
как описано здесь . Ниже приведен пример, который должен работать для вас:Таким образом, вы разделяете имена файлов с
\0
символами null ( ), это означает, что изменение в пространстве и другие специальные символы не вызовут проблем.Чтобы обновить архив с файлами, которые
find
находятся, вы можете передать его вывод непосредственноtar
:Обратите внимание, что вам не нужно делать различий между тем, существует ли архив или нет
tar
. Также обратите внимание на использование-printf
здесь, чтобы избежать включения./
бита в архив.источник
./
как tar../.tar tar: ./archive.tar: file is the archive; not dumped
if [[ "$FILE" == "./" ]]; then
continue
./
немного с-printf
SEE обновленного ответом. Однако это не должно иметь никакого значения, если он включен или нет, поскольку он просто ссылается на текущий каталог. Я также включил альтернативнуюfind/tar
комбинацию, которую вы можете использовать.sort
результаты перед их повторением, вам понадобитсяsort -z
нулевой разделитель.Попробуйте процитировать
for
цикл так:Без кавычек bash вообще не обрабатывает пробелы и символы новой строки (
\n
) ...Также попробуйте установить
источник
comm
для сравнения отсортированных списков файлов, и имена файлов содержали пробелы, несмотря на то, что в кавычках переменные не работали. Затем я увидел cyberciti.biz/tips/handling-filenames-with-spaces-in-bash.html и решение установки $ IFS с IFS = $ (echo -en "\ n \ b") сработало для меня.Это работает и проще:
Благодарим Рупу ( https://github.com/rupa/z ) за этот ответ.
источник
В дополнение к правильному цитированию, вы можете указать
find
использовать разделитель NULL, а затем прочитать и обработать результаты вwhile
циклеЭто должно обрабатывать любые имена файлов, которые соответствуют POSIX - см.
man find
источник
источник
Я сделал что-то вроде этого, чтобы найти файлы, которые могут содержать пробелы.
Работал как шарм :)
источник
Большинство ответов здесь прерываются, если в имени файла есть символ новой строки. Я использую 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 выполняет команду, используя системный вызов, так что пробелы и символы новой строки сохраняются (скорее, это труба, которая потребует цитирования специальных символов). Обратите внимание, что tar -c работает независимо от того, существует архив или нет, и что (по крайней мере, с помощью bash) ни {}, ни + не нужно заключать в кавычки.
источник
Как предложил minerz029, вам нужно процитировать расширение
find
команды. Вы также должны процитировать все замены$FILE
в вашем цикле.Обратите внимание, что
$()
синтаксис должен быть предпочтительнее использования обратных галочек; см этого вопроса U & L . Я также удалил[[
ключевое слово и заменил его[
командой, потому что это POSIX.источник
[[
и[
, кажется,[[
это новее и поддерживает больше функций, таких как глобализация и сопоставление регулярных выражений.[[
только вbash
, хотя, неsh
[[
болтовней. Согласно вики Грега , внутри не происходит никаких шатаний[[
.[ "ab" == a? ] && echo "true"
тогда[[ "ab" == a? ]] && echo "true"
a*
означает «a, за которым следует любое количество символов», а не «все файлы, чьи имена начинаются сa
любого количества символов после». Попробуйте[ ab = a* ] && echo true
против[[ ab == a* ]] && echo true
.[[
все еще делает регулярные выражения, пока[
нет. Должно быть, запутался