평가하다

평가하다
$ FILE="$(mktemp)"
$ printf "a\0\n" > "$FILE"
$ od -tx1z "$FILE"
0000000 61 00 0a                                         >a..<
0000003

여태까지는 그런대로 잘됐다.

위 내용을 bash 스크립트로 캡슐화했습니다.

#! /bin/bash

cmd=("$@")
FILE="$(mktemp)"
eval "${cmd[@]}" > "$FILE"
od -tx1z "$FILE"

하지만

$ script printf 'a\0\n' 
0000000 61 30 6e                                         >a0n<
0000003

출력이 \0리터럴 문자열이 되는 이유는 무엇입니까? 이런 일이 발생하지 않도록 하려면 어떻게 해야 합니까?


이 게시물에서는별로 중요하지 않습니다. 내 문제는 일부 명령을 bash 스크립트로 래핑하려고 시도한 결과입니다.NUL 제거로 인한 명령 확장 방지:

FILE="$(mktemp)"
printf "a\0\n" > "$FILE"
S="$(uuencode -m "$FILE" /dev/stdout)"
uudecode -o /dev/stdout <(printf "$S") | od -tx1
rm "$FILE"

답변1

출력이 \0리터럴 문자열이 되는 이유는 무엇입니까? 이런 일이 발생하지 않도록 하려면 어떻게 해야 합니까?

.eval​ 백슬래시로 이스케이프 처리된 0과 0을 사용하여 eval명령을 실행하고 백슬래시를 제거한 후 그대로 둡니다.printf a\0\nn

대신 를 사용하면 이를 효과적으로 방지할 수 있습니다 eval. 을 사용하면 "$@" > "$FILE" 스크립트 인수로 지정된 명령을 실행할 수 있어야 합니다. 하지만 이 경우에는 를 사용할 수 없습니다 eval. 또는 명령을 인수로 전달할 필요가 없도록 전체를 다시 디자인할 수 있습니다.

명령 확장이 NUL을 제거하는 것을 방지하기 위해 일부 명령을 bash 스크립트로 래핑하려고합니다.

S="$(uuencode -m "$FILE" /dev/stdout)"

이것이 여기서 문제인가요? uuencode -mNUL 바이트가 생성되어서는 안 됩니다. 바이너리 데이터를 텍스트로 인코딩하므로 정반대입니다.

마지막 스크립트는 a, NUL 및 개행 문자를 작성하여 에 전달합니다. 그러면 16진수 표현이나 이와 유사한 내용이 $FILE인쇄됩니다 .od0000000 61 00 0a

답변2

NUL을 stdout, stderr로 출력하거나 stdin에서 받을 수 있습니다.
무엇이든 "내부"포착그리고 (거의) NUL을 사용하면 문제가 됩니다.

stdout에 NUL을 발행할 수 있습니다.

$ printf 'a\0b' | sed -n l
a\000b$

또는:

$ printf 'a\0b' | cat -A
a^@b

파일도 있습니다:

$ printf 'a\0b' >outfile

그리고정확히이는 스크립트에도 적용됩니다.

평가하다

첫 번째 스크립트의 문제점은 다음을 사용하고 있다는 것입니다 eval.

$ cmd=(printf 'a\0b\n')
$ echo "${cmd[@]}"
printf a\0b\n

$ eval echo "${cmd[@]}"
printf a0bn

두 번째 루프에서는 백슬래시를 구문 분석하는 쉘 라인이 제거됩니다.
평가판을 사용하지 마십시오.

$ "${cmd[@]}"| sed -n l
a\000b$

확장하다

이는 printf내장 및 stdoutNUL 작업이 모두 가능하다는 것을 증명합니다.

그러나 이것은 실패합니다.

$ printf '%s\n' "$(printf 'a\0b')" | cat -A
bash: warning: command substitution: ignored null byte in input
ab$

(bash 4.4+에는) 경고 메시지도 있습니다.

즉, 쉘(대부분의 쉘)은 내부적으로 C 문자열을 사용하며 C 문자열은 첫 번째 NUL로 종료됩니다. 일부 쉘은 "명령 확장"의 첫 번째 NUL에서 잘립니다.

$ ksh -c 'echo $(printf "a\0b\n")|sed -n l'    # also yash
a$

일부는 NUL을 제거했습니다.

$ bash -c 'echo $(printf "a\0b\n")|sed -n l'
ab$

일부는 NUL을 공백으로 변경하기도 합니다.

$ zsh -c 'echo $(printf "a\0b\n")|sed -n l'
a b$

변수 할당에서도 비슷한 문제가 발생합니다.

코딩

예, 링크한 답변은 uuencode파일 내용을 인코딩(및 디코딩)합니다.

더 간단한 접근 방식은 다음과 같습니다 xxd(8진수 덤프를 되돌릴 수 있음).

FILE="$(mktemp)"
printf "a\0b\n" > "$FILE"
S=$(xxd -p "$FILE")
xxd -r -p <(printf '%s' "$S") | xxd -p
rm "$FILE"

관련 정보