Bash에서 null 바이트를 어떻게 사용합니까? 이와 같은 것이 잘 작동하지만 (줄 바꿈으로

Bash의 파일 경로에는 null 바이트 (제로 값 바이트 $'\0')를 제외한 모든 문자가 포함될 수 있으므로 null 바이트를 구분 기호로 사용하는 것이 가장 좋습니다. 예를 들어의 출력이 find다른 프로그램으로 전송 될 경우 -print0옵션이있는 버전 을 사용하는 것이 좋습니다 find.

그러나 이와 같은 것이 잘 작동하지만 (줄 바꿈으로 구분 된 파일 경로 인쇄-걱정하지 마십시오. 이것은 단지 데모 일뿐입니다. 실제로 실제 스크립트에서는하지 않습니다) :

find -print0 \
  | while IFS= read -r -d $'\0' ; do echo "$REPLY" ; done

이런 식으로 작동 하지 않습니다 :

for file in * ; do echo -n "$file"$'\0' ; done \
  | while IFS= read -r -d $'\0' ; do echo "$REPLY" ; done

for-loop 부분 만 시도 하면 null 바이트 없이 모든 파일 이름을 함께 인쇄한다는 것을 알았습니다 .

왜 이런거야? 무슨 일이야?



답변

Bash는 내부적으로 C 스타일 문자열을 사용하며 null 바이트로 끝납니다. 이는 Bash 문자열 (예 : 변수 값 또는 명령의 인수)이 실제로 널 바이트를 포함 할 수 없음을 의미합니다. 예를 들어이 미니 스크립트는 다음과 같습니다.

foobar=$'foo\0bar'    # foobar='foo' + null byte + 'bar'
echo "${#foobar}"     # print length of $foobar

실제로 인쇄 3하기 때문에, $foobar단지 실제로 'foo'다음은 bar문자열의 끝 후에 온다.

마찬가지로 부품 에 대해 알지 못 하기 때문에 echo $'foo\0bar'그냥 인쇄합니다 .fooecho\0bar

보시다시피, \0시퀀스는 실제로 $'...'스타일 문자열 에서 매우 오도됩니다 . 문자열 내부의 null 바이트처럼 보이지만 그런 식으로 작동하지 않습니다. 첫 번째 예에서 read명령은 -d $'\0'입니다. 이것은 작동하지만 작동하기 때문에 만 가능 -d ''합니다! (즉의 명시 적으로 문서화 기능이 아니다 read, 그러나 나는 같은 이유로 작동 가정 : ''빈 문자열이, 그 종료 널 바이트가 바로 온다 그래서. “의 첫 번째 문자 사용으로 설명되어 있습니다 DELIM를 “나는 심지어 작품을 추측 “첫 번째 문자”가 문자열의 끝을 지났다면!)-d delim

당신이 알고 그러나 find예, 그것은 이다 명령이 널 바이트를 출력하고, 그 바이트가 입력으로 읽고 다른 명령에 파이프 할 할 할 수 있습니다. 그중 어느 것도 Bash 내부의 문자열에 null 바이트를 저장하는 것에 의존하지 않습니다 . 두 번째 예의 유일한 문제 $'\0'는 명령에 대한 인수로 사용할 수 없다는 것 입니다. echo "$file"$'\0'원하는 경우에만 null 바이트를 행복하게 인쇄 할 수 있습니다.

따라서을 사용하는 대신 스타일 문자열 과 동일한 종류의 이스케이프 시퀀스를 지원하는을 echo사용할 수 있습니다 . 이렇게하면 문자열 안에 null 바이트가 없어도 null 바이트를 인쇄 할 수 있습니다. 다음과 같이 보일 것입니다.printf$'...'

for file in * ; do printf '%s\0' "$file" ; done \
  | while IFS= read -r -d '' ; do echo "$REPLY" ; done

또는 단순히 이것 :

printf '%s\0' * \
  | while IFS= read -r -d '' ; do echo "$REPLY" ; done

(참고 : echo실제로 널 바이트를 -e처리 \0하고 인쇄 할 수 있는 플래그가 있지만 파일 이름의 특수 시퀀스를 처리하려고 시도하므로 printf접근 방식 이보다 강력합니다.)


덧붙여, 어떤 조개가 않습니다 null의 내부 문자열을 바이트 수 있습니다. 예를 들어 Zsh에서는 기본 설정을 가정하여 정상적으로 작동합니다. 그러나 쉘과 상관없이 Unix와 같은 운영 체제는 프로그램에 대한 인수 내부에 널 바이트를 포함시키는 방법을 제공하지 않으므로 (프로그램 인수가 C 스타일 문자열로 전달되므로) 항상 제한이 있습니다. (이 예제는 echo쉘이 내장되어 있기 때문에 Zsh에서만 작동 할 수 있으므로 Zsh는 다른 프로그램을 호출하기 위해 OS 지원에 의존하지 않고 호출 할 수 있습니다. command echo대신에 사용 echo하면 내장 echo프로그램을 무시하고에서 독립 실행 형 프로그램을 사용했습니다 $PATH. Zsh에서 Bash와 동일한 동작을 볼 수 있습니다.)