複数のサブフォルダー内のすべてのファイルを検索し、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。
Whileループで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
for
でfind
を使用することは、ここでは間違ったアプローチです。たとえば、 this writeup 開いているワームの缶についてを参照してください。
推奨されるアプローチは、 here の説明に従ってfind
、while
およびread
を使用することです。以下はあなたのために働くはずの例です:
find . -type f -name '*.*' -print0 |
while IFS= read -r -d '' file; do
printf '%s\n' "$file"
done
このように、ファイル名をヌル(\0
)文字で区切ることにより、スペースやその他の特殊文字の違いが問題を引き起こさないことを意味します。
find
が見つけるファイルでアーカイブを更新するには、その出力をtar
に直接渡すことができます。
find . -type f -name '*.*' -printf '%p\0' |
tar --null -uf archive.tar -T -
アーカイブが存在するかどうかを区別する必要はないことに注意してください。tar
はアーカイブを適切に処理します。アーカイブに-printf
ビットが含まれないように、ここで./
を使用することにも注意してください。
次のように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
この回答は、Rupa( https://github.com/rupa/z )の功績によるものです。
適切な引用に加えて、find
にNULLセパレーターを使用するように指示し、while
ループで結果を読み取って処理することができます。
while read -rd $'\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.
スペースを含む可能性のあるファイルを見つけるために、このようなことをしました。
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
魅力のように働いた:)
find . <find arguments> -print0 | xargs -0 grep <pattern>
ファイル名に改行文字が含まれている場合、ほとんどの回答は中断します。私は15年以上もbashを使用していますが、インタラクティブのみです。
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では){}も+も引用符で囲む必要がないことに注意してください。