스크립트 결과를 인쇄할 때 printf가 IFS를 무시하는 이유는 무엇입니까?

스크립트 결과를 인쇄할 때 printf가 IFS를 무시하는 이유는 무엇입니까?

이건 후속작이야질문SO에 게시되었습니다.

except나는 이와 같이 주어진 파일 이름/디렉토리를 제외한 모든 파일 이름/디렉토리를 인쇄해야 하는 스크립트를 작성했습니다 .

$ ls
a b c d
$ rm $(except b d)
$ ls
b d

지금까지 작성한 스크립트는 다음과 같습니다.

shopt -s extglob
shopt -s nullglob

old_ifs=$IFS
IFS='|'
matches="!($*)"
IFS=' '

printf '%s' $matches
IFS=$old_ifs

이것은 어느 정도 작동하지만 주요 문제는 printf가 (공백) IFS설정을 존중하지 않는 것 같다는 것입니다 .

사이에 공백 없이 인쇄됩니다. 대신 echo를 사용하면 작동합니다(추가된 줄 바꿈 제외). 그러나 호환성상의 이유로 이 작업을 수행하려면 printf를 사용하고 싶습니다. 이 목표를 어떻게 달성할 수 있나요? 내가 뭘 잘못했나요?

또한 수정자를 사용해 보았 %q으나 원하는 결과가 나오지 않았습니다.

printf '%q' $matches

답변1

$ ls
a b c d
$ rm $(except b d)
$ ls
b d

"except"명령에 전달하기 전에 쉘이 출력을 분할(및 추가 확장)하는 방법을 결정할 방법이 없기 때문에 이것은 작동하지 않거나 적어도 신뢰할 수 없습니다 rm.

귀하의 질문에 대답하기 위해 printf는 사용되지 않습니다 $IFS. IFS를 사용하는 유일한 명령은 입니다 read. 그 외에 쉘은 연결의 토큰화 및 위치 인수에 $IFS를 사용합니다 "$*".

다음을 수행할 수 있습니다.

 printf '%s ' $matches

또는

 printf '%s\n' $matches

하지만 다시,

 rm $(except a b)

except해당 명령줄을 해석하는 셸은 자체 상황에 따라 출력을 분할하고 $IFS(기본값은 공백, 탭 또는 줄 바꿈이므로 공백 이상 을 사용해도 \n차이가 없음) 와일드카드도 확장합니다.

a따라서 and 이외의 파일이 band "this file.txt"이면 **a**출력 except되고 and 를 "this file.txt **a** "제거하려고 시도하게 됩니다 (해당 이름의 모든 파일로 확장되므로 ).thisfile.txta**a**a

후행 공백 없이 공백과 일치 항목을 연결하려면 다음을 수행할 수 있습니다.

IFS=
set -- $matches
IFS=' '
matches="$*"

관련 정보