$ 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\n
n
대신 를 사용하면 이를 효과적으로 방지할 수 있습니다 eval
. 을 사용하면 "$@" > "$FILE"
스크립트 인수로 지정된 명령을 실행할 수 있어야 합니다. 하지만 이 경우에는 를 사용할 수 없습니다 eval
. 또는 명령을 인수로 전달할 필요가 없도록 전체를 다시 디자인할 수 있습니다.
명령 확장이 NUL을 제거하는 것을 방지하기 위해 일부 명령을 bash 스크립트로 래핑하려고합니다.
S="$(uuencode -m "$FILE" /dev/stdout)"
이것이 여기서 문제인가요? uuencode -m
NUL 바이트가 생성되어서는 안 됩니다. 바이너리 데이터를 텍스트로 인코딩하므로 정반대입니다.
마지막 스크립트는 a
, NUL 및 개행 문자를 작성하여 에 전달합니다. 그러면 16진수 표현이나 이와 유사한 내용이 $FILE
인쇄됩니다 .od
0000000 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
내장 및 stdout
NUL 작업이 모두 가능하다는 것을 증명합니다.
그러나 이것은 실패합니다.
$ 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"