ファイル名にスペースを含む単一のファイルを移動すると、次のように動作します。
$ mv "file with spaces.txt" "new_place/file with spaces.txt"
これで、スペースを含めることができるファイルのリストがあり、それを移動したいと思います。たとえば、
$ echo "file with spaces.txt" > file_list.txt
$ for file in $(cat file_list.txt); do mv "$file" "new_place/$file"; done;
mv: cannot stat 'file': No such file or directory
mv: cannot stat 'with': No such file or directory
mv: cannot stat 'spaces.txt': No such file or directory
最初の例はうまくいきますが、2番目の例はうまくいきません。どのように動作させることができますか?
ベストアンサー1
いつも、いつも使ってくださいfor foo in $(cat bar)
。これは一般的に知られているエラーです。バッシュトラップ番号1。以下を使用する必要があります。
while IFS= read -r file; do mv -- "$file" "new_place/$file"; done < file_list.txt
for
ループを実行すると、bashは読み取る内容にトークン化を適用します。つまり、、、および次a strange blue cloud
に読み込まれます。a
strange
blue
cloud
$ cat files
a strange blue cloud.txt
$ for file in $(cat files); do echo "$file"; done
a
strange
blue
cloud.txt
比較:
$ while IFS= read -r file; do echo "$file"; done < files
a strange blue cloud.txt
それとも頑張るならウルク:
$ cat files | while IFS= read -r file; do echo "$file"; done
a strange blue cloud.txt
したがって、while
ループは入力を読み取り、をread
使用して各行を変数に割り当てます。IFS=
入力フィールド区切り文字をNULL *に設定すると、この-r
オプションはread
バックスラッシュエスケープを解釈しないようにします(タブの代わりに\t
スラッシュ+として扱われます)。t
afterは、「--の後のすべてをオプションではなく引数として扱う」ことを--
意味します。これにより、正しいファイル名で始まるファイル名を適切に処理できます。mv
-
* 厳密に言えば、ここでは必要ありません。この場合の唯一の利点は、read
先行または末尾のスペースを削除しないことです。ただし、改行文字を含むファイル名を処理する必要があるか、通常は任意のファイル名を処理できます。