bash는 16 진수 값 0x00을 변수에 저장할 수 없습니다


11

dd로 몇 가지 트릭을 시도하고 있습니다. 16 진수 값을 "header"라는 변수에 저장하여 dd로 파이프하는 것이 가능하다고 생각했습니다.

변수가없는 첫 번째 단계는 다음과 같습니다.

$ echo -ne "\x36\xc9\xda\x00\xb4" |dd of=hex
$ hd hex

00000000  36 c9 da 00 b4                                    |6....|
00000005

그 후 나는 이것을 시도했다 :

$ header=$(echo -ne "\x36\xc9\xda\x00\xb4") 
$ echo -n $header | hd

00000000  36 c9 da b4                                       |6...|
00000004

보시다시피 변수 \x00에서 값을 잃었습니다 $header. 누구든지이 행동에 대한 설명이 있습니까? 이것은 나를 미치게합니다.


나는 얻는다 bash: warning: command substitution: ignored null byte in input.
Kusalananda

따옴표가 누락 header="$(echo -ne "\x36\xc9\xda\x00\xb4")"; echo -n "$header" | hd되었지만 동일한 결과를 제공 해야합니다 .
ctrl-alt-delor

이것은 작동 header="\x36\xc9\xda\x00\xb4"; echo -n "$header" | hd하지만 인간이 읽을 수있는 양식을 저장하는 것과는 다릅니다.
ctrl-alt-delor

답변:


16

Bash는 C 스타일 문자열을 사용하기 때문에 문자열에 널 바이트를 저장할 수 없습니다.이 문자열은 종료자를 위해 널 바이트를 예약합니다. 따라서 Bash가 중간에 저장하지 않고 널 바이트를 포함하는 시퀀스를 파이프하기 위해 스크립트를 다시 작성해야합니다. 예를 들어 다음과 같이 할 수 있습니다.

printf "\x36\xc9\xda\x00\xb4" | hd

그건 그렇고, 당신은 필요하지 않습니다 echo; Bash를 printf다른 많은 간단한 작업에 사용할 수 있습니다 .

또는 체인 대신 임시 파일을 사용할 수 있습니다.

printf "\x36\xc9\xda\x00\xb4" > /tmp/mysequence
hd /tmp/mysequence

물론 이것은 파일 /tmp/mysequence이 이미 존재할 수 있다는 문제가 있습니다. 이제 임시 파일을 작성하고 경로를 문자열로 저장해야합니다.

또는 프로세스 대체를 사용하여이를 피할 수 있습니다.

hd <(printf "\x36\xc9\xda\x00\xb4")

<(command)연산자의 출력을 수신 할 파일 시스템의 명명 된 파이프를 생성 command. hd첫 번째 인수로 파이프에 대한 경로를받습니다.이 파이프는 거의 모든 파일처럼 열고 읽을 수 있습니다. /unix//a/17117/136742 에서 자세한 내용을 확인할 수 있습니다 .


1
정확하지만 이것은 정확한 이유가 아니라 구현 세부 사항입니다. 나는 그것을 보았고 POSIX 표준 에는 실제로이 행동이 필요 하므로 실제 이유가 있습니다. (일부 지적했듯이, zsh그렇게 할 수는 있지만 논 POSIX 모드에서만 가능합니다.) 나는 이것을 구현할 가치가 있는지 궁금해하기 때문에 실제로 그것을 보았습니다 mksh...
mirabilos

@mirabilos, 당신은 그것을 확장 하시겠습니까? AFAICT, 출력에 NUL 문자가있을 때 명령 대체에 대해 POSIX마다 동작이 지정되지 않으며 POSIX 모드의 zsh에 대해 유일하게 생각할 수있는 유일한 차이점은 sh에뮬레이션 \0에서 기본값이에 있지 않다는 것입니다 $IFS. 에뮬레이션에서 echo "$(printf 'a\0b')"여전히 작동합니다 . shzsh
Stéphane Chazelas

3
@mirabilos 쉘이 POSIX 표준보다 10 년 이상 앞서 있다고 생각 하면 실제 실제 이유는 쉘이 C 스타일 문자열을 사용하고 표준이 그 주위에 구축되었다는 것을 알 수 있습니다.
giusti

printf와 echo에 대한 자세한 논의를 위해 좋은 Q를 찾았습니다. unix.stackexchange.com/questions/65803/…
Paulb

8

zsh변수에 NUL 문자를 저장할 수있는 유일한 쉘인 대신 사용할 수 있습니다 . 해당 문자는 기본값 $IFSin에 zsh있습니다.

nul=$'\0'

또는:

nul=$'\x0'

또는

nul=$'\u0000'

또는

nul=$(printf '\0')

그러나 인수 및 환경 변수가 시스템 호출에 전달되는 NUL 구분 문자열 (쉘이 아닌 시스템 API의 제한) 이므로 실행 되는 명령에 인수 또는 환경 변수와 같은 변수를 전달할 수 execve()없습니다. ). 에서가 zsh, 당신은 그러나 NUL 함수 또는 명령 내장 인수로 바이트를 전달할 수 있습니다.

echo $'\0' # works
/bin/echo $'\0' # doesn't

1
"zsh를 대신 사용할 수 있습니다." 고마워요-저는 초보자로서 배쉬 스크립팅을 가르치고 있습니다. 다른 구문과 혼동하고 싶지 않습니다. 그러나 제안 해 주셔서 대단히 감사합니다
Frank

실제로 zsh질문에 구문 을 사용 했습니다. echo -n $header콘텐츠의 전달을 의미하기 $header위해 마지막 인자로 변수 echo -n이다 zsh(또는 fish또는 rc또는 es) 구문 아닌 bash 구문. 에서 bash가, 매우 다른 의미를 . 더 일반적으로 zsh같다 ksh( bash는 GNU 쉘, 다소의 파트 복제되고 ksh, 유닉스 사실상 쉘에게)하지만 함께 Bourne 씨의 디자인 특질의 대부분이 고정 (기능과 특징을 많이하고, 많은 쉘을 더 사용자 친화적 / 덜 놀라운).
Stéphane Chazelas

주의 : zsh는 때때로 0 바이트를 변경할 수 있습니다 echo $(printf 'ab\0cd') | od -vAn -tx1c .`61 62 20 63 64 0a`를 인쇄합니다. 즉, NUL이 있어야합니다.
Isaac

1
그리고 그것은 다른 (없음, 없음) 쉘이 재현하지 않는 것입니다. 따라서 스크립트는 zsh에서 매우 특별한 방식으로 동작합니다. 내 의견으로는 : zsh는 너무 영리하려고합니다.
Isaac

2
zsh 스크립트 작성에 익숙해 졌다는 POSIX sh 표준에있는 디자인의 잘못된 기능을 "수정"하면 다른 쉘에서 연습 할 경우 버그가있는 관행에 익숙해 짐을 의미합니다. 이것은 기술이나 습관이 전이되지 않는 다른 언어와 달리 구문과 관련하여 문제가되지는 않지만 실제로는 그렇지 않습니다.
Charles Duffy 2012
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.