다음 Linux 셸 명령이 있습니다.
echo $(python3 -c 'print("Test"+"\0"+"M"*18)') | nc -u [IP] [PORT]
내 의도는 명령문의 출력을 print
netcat 명령으로 파이프하는 것입니다. netcat 명령은 기본적으로 들어오는 문자열의 표준 출력을 반환하는 일부 서비스에 대한 소켓을 만듭니다.
여기서 문제는 이 명령을 실행하려고 할 때 다음 메시지가 표시된다는 것입니다.
-bash: warning: command substitution: ignored null byte in input
; 내 null 바이트가 \0
무시됩니다. 하지만 저는 null 바이트가 무시되는 것을 원하지 않습니다.
null 바이트를 무시하지 않고 내가 지정한 대로 정확히 입력을 받도록 시스템에 지시하려면 어떻게 해야 합니까?
Google 검색을 몇 번 해봤지만 솔직히 별로 도움이 되지 않았습니다. 또한, 훌륭한 기사에 대한 링크를 제공해 주시면 매우 감사하겠습니다.
편집하다
사용 에 유효합니다 printf
.
일반적으로 합격 python3 -c 'print("Test"+"\0"+"M"*18)'
도 유효합니다. 귀중한 @cas 설명. 나는 printf
이것이 더 빠르기 때문에 아마도 이것을 고수할 것이라고 생각합니다(물론 제 경우에는 속도가 특별히 중요하지 않지만).
모든 기여자에게 감사드립니다 :-).
답변1
Bash의 문자열할 수 없다NUL 바이트를 포함하고 명령 대체의 모든 출력을 포함합니다. Bash 변수에는 NUL도 포함될 수 없습니다. 이는 무시하거나 재정의할 수 없습니다(일부 명령에서는 개행 표시와 마찬가지로 NUL 표시 printf
로 사용하여 문제를 해결할 수 있지만 ).\0
\n
nc
@CharlieWilson의 답변에서와 같이 명령 대체 없이 Python의 출력을 Python으로 직접 파이프할 수 있지만 echo
그럴 필요도 없습니다. Bash에는 printf
원하는 작업을 수행할 수 있는 기능이 내장되어 있습니다. 예를 들어
{ printf 'Test\0'; printf -- '%.0sM' {1..18}; } | nc -u [IP] [PORT]
이는 그룹 명령( { list; }
)을 사용하여 먼저 \0
printf를 사용하여 "Test" 및 NUL 바이트( )를 인쇄한 다음 다시 printf를 사용하여 너비가 0인 문자열( %.0s
)을 인쇄하고 이어서 M
18번을 인쇄합니다. 전체 그룹 명령의 출력은 으로 파이프됩니다 nc
.
printf
이는 형식이 "모든 인수를 소비하기 위해 필요에 따라 재사용"(참고자료 참조 help printf
)되고 중괄호 확장이 1에서 18까지의 정수로 확장되어 0이 하나만 있는 printf 형식 문자열을 제공하기 때문에 작동합니다 {1..18}
. 매개변수는 18개입니다(너비 문자열 필드 및 문자 그대로의 "M" 문자입니다. 따라서 18M 문자가 출력됩니다.
대신 hexdumper(예: or )에 파이프하여 그룹 명령이 출력하는 xxd
내용을 정확하게 확인할 수 있습니다 .hd
nc
$ { printf 'Test\0'; printf -- '%.0sM' {1..18}; } | hd
00000000 54 65 73 74 00 4d 4d 4d 4d 4d 4d 4d 4d 4d 4d 4d |Test.MMMMMMMMMMM|
00000010 4d 4d 4d 4d 4d 4d 4d |MMMMMMM|
00000017
이렇게 하면 다섯 번째 문자가 NUL( )임을 알 수 있습니다 00
.
print
Python이 자동으로 줄 바꿈( 0a
) 을 추가하기 때문에 Python의 출력은 약간 다릅니다 .
$ python3 -c 'print("Test"+"\0"+"M"*18)' | hd
00000000 54 65 73 74 00 4d 4d 4d 4d 4d 4d 4d 4d 4d 4d 4d |Test.MMMMMMMMMMM|
00000010 4d 4d 4d 4d 4d 4d 4d 0a |MMMMMMM.|
00000018
전송하려는 프로그램에 nc
개행 문자가 필요한 경우 print it 을 사용할 수 있습니다 printf '\n'
. 또는 echo
.
$ { printf 'Test\0'; printf -- '%.0sM' {1..18}; echo; } | hd
00000000 54 65 73 74 00 4d 4d 4d 4d 4d 4d 4d 4d 4d 4d 4d |Test.MMMMMMMMMMM|
00000010 4d 4d 4d 4d 4d 4d 4d 0a |MMMMMMM.|
00000018
참고: 그룹 명령에 대한 자세한 내용은 다음을 참조 man bash
하고 검색 하세요 Compound Commands
.
{ list; }
list
현재 쉘 환경에서 실행하면 됩니다.list
~ 해야 하다개행 또는 세미콜론으로 종료합니다.이를 그룹 명령이라고 합니다. 반환 상태는 목록의 종료 상태입니다.
(
메타 문자와 달리 및)
는{
예약어}
이므로 인식된 예약어가 허용되는 곳에 나타나야 합니다. 하이픈을 사용하지 않기 때문에list
공백이나 기타 쉘 메타 문자로 구분해야 합니다.
그런데 printf를 사용하는 것이 Python을 실행하고 작은 Python 스크립트를 컴파일하는 오버헤드를 피하기 때문에 Python을 사용하는 것보다 빠릅니다. 이것은 현대 시스템의 일회성 명령과 관련이 없지만 루프에서 실행되는 경우에는 관련이 없습니다. 예를 들어, 약 10년 전의 6코어 AMD Phenom II 1090T에서는 다음과 같습니다.
$ time { printf 'Test\0'; printf -- '%.0sM' {1..18}; }
TestMMMMMMMMMMMMMMMMMM
real 0m0.000s user 0m0.000s sys 0m0.000s
$ time python3 -c 'print("Test"+"\0"+"M"*18)'
TestMMMMMMMMMMMMMMMMMM
real 0m0.036s user 0m0.028s sys 0m0.008s
printf는 실제로 0초가 걸리지 않고 시간이 더 걸리지만 $TIMEFORMAT 문자열로 표현하기에는 시간이 너무 짧습니다.
Perl은 작은 스크립트를 시작, 컴파일 및 실행하는 데 Python보다 약간 빠르지만 여전히 쉘 루프에서 반복적으로 실행하고 싶지는 않습니다.
$ time perl -e 'print "Test\0" . "M" x 18 . "\n"'
TestMMMMMMMMMMMMMMMMMM
real 0m0.008s user 0m0.000s sys 0m0.009s
또는 훨씬 더 빠른 Perl의 printf를 사용하십시오.
$ time perl -e 'printf "Test\0%s\n", "M" x 18'
TestMMMMMMMMMMMMMMMMMM
real 0m0.003s user 0m0.003s sys 0m0.000s
답변2
echo
나는 그것이 문제이고 불필요하다고 믿습니다 .
이 라인을 고려해주세요.
python3 -c 'print("Test"+"\0"+"M"*18)' | nc -u [IP] [PORT]