名前は同じですが、サブディレクトリが異なる複数のファイルをディレクトリにコピーし、ソースファイルのパスに基づいて名前を変更しようとします。私はbashで意図したことを達成するためにforループを使用していますが、zshでは奇妙に動作します。
コマンド(読みやすくするために改行が追加されました):
for f in */Flavors/*/stuff1/filename.txt;
do l=$(echo $f | cut -d'/' --output-delimiter '' -f1,3);
dest=/stuff2/${l}.utf8.txt;
echo $f $dest;
cp -v -- $f $dest;
done
zshで出力します。出力ファイル名を「EnglishAU.utf8.txt」に設定しようとしましたが、「English」、「French」、「Spanish」にすぎません。echo
ループには$dest
正しいパスが含まれているように見えますが、cp
間違ったパスを使用してください。
English/Flavors/AU/stuff1/filename.txt /stuff2/EnglishAU.utf8.txt
`English/Flavors/AU/stuff1/filename.txt' -> `/stuff2/English'
English/Flavors/UK/stuff1/filename.txt /stuff2/EnglishUK.utf8.txt
`English/Flavors/UK/stuff1/filename.txt' -> `/stuff2/English'
English/Flavors/US/stuff1/filename.txt /stuff2/EnglishUS.utf8.txt
`English/Flavors/US/stuff1/filename.txt' -> `/stuff2/English'
French/Flavors/CA/stuff1/filename.txt /stuff2/FrenchCA.utf8.txt
`French/Flavors/CA/stuff1/filename.txt' -> `/stuff2/French'
French/Flavors/FR/stuff1/filename.txt /stuff2/FrenchFR.utf8.txt
`French/Flavors/FR/stuff1/filename.txt' -> `/stuff2/French'
Spanish/Flavors/ES/stuff1/filename.txt /stuff2/SpanishES.utf8.txt
`Spanish/Flavors/ES/stuff1/filename.txt' -> `/stuff2/Spanish'
Spanish/Flavors/OT/stuff1/filename.txt /stuff2/SpanishOT.utf8.txt
`Spanish/Flavors/OT/stuff1/filename.txt' -> `/stuff2/Spanish'
上記のように、これはbashで期待どおりに機能します。 zshは何をしていますか?
答え1
これは、cut
出力にNULL文字が出力されるために発生します。 NULL文字を含むプログラムにはパラメータを渡すことはできません(参照:これ)。
Bashでは、bashは文字列のNULL文字を処理できず、それを削除するため、これは機能します。 Zshはより強力で、NULL文字を処理できます。ただし、文字列がプログラムに渡された場合は、引き数の終わりを表すnullも含まれます。
これを詳しく見てみましょう。
$ echo 'English/Flavors/AU/stuff1/filename.txt' | cut -d'/' --output-delimiter '' -f1,3 | xxd
0000000: 456e 676c 6973 6800 4155 0a English.AU.
ここでは、ファイルの1つをシミュレートしてを渡します。出力の間にNULL文字がある cut
ことに注意してください。xxd
English
AU
それでは、残りのスクリプトを実行してシミュレーションしてみましょう。
$ l=$(echo 'English/Flavors/AU/stuff1/filename.txt' | cut -d'/' --output-delimiter '' -f1,3)
$ dest=/stuff2/${l}.utf8.txt
$ echo "$dest" | xxd
0000000: 2f73 7475 6666 322f 456e 676c 6973 6800 /stuff2/English.
0000010: 4155 2e75 7466 382e 7478 740a AU.utf8.txt.
最後にNULLがあることに注意してくださいEnglish
。組み込みシェルなのでecho
正しく表示されます。echo
外部を使用している場合echo
でも、この問題が発生します。
$ /bin/echo "$dest" | xxd
0000000: 2f73 7475 6666 322f 456e 676c 6973 680a /stuff2/English.
PS:あなたもそれを引用する必要があります:-)
解決策はを使用するのではcut
なくawk
使用することです。
$ echo 'English/Flavors/AU/stuff1/filename.txt' | awk -F/ '{ print $1$3 }' | xxd
0000000: 456e 676c 6973 6841 550a EnglishAU.