이름은 같지만 하위 디렉터리가 다른 여러 파일을 디렉터리로 복사하고 원본 파일의 경로에 따라 이름을 변경하려고 합니다. 나는 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 문자가 출력되기 때문에 발생합니다. 널 문자가 포함된 프로그램에는 매개변수를 전달할 수 없습니다(참조:이것).
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.
여기서는 파일 중 하나를 시뮬레이션하여 을 전달합니다 . 출력의 와 사이에 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.
추신: 당신도 그것을 인용해야 합니다 :-)
해결책은 을 사용하는 것이 cut
아니라 awk
사용하는 것입니다.
$ echo 'English/Flavors/AU/stuff1/filename.txt' | awk -F/ '{ print $1$3 }' | xxd
0000000: 456e 676c 6973 6841 550a EnglishAU.