bash ไม่สามารถเก็บ hexvalue 0x00 ในตัวแปรได้


11

ฉันพยายามจะเล่นกลกับ dd ฉันคิดว่ามันจะเป็นไปได้ที่จะเก็บ hexvalues ​​บางอย่างในตัวแปรที่เรียกว่า "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

คุณไม่สามารถเก็บค่า null ในสตริงได้เนื่องจาก Bash ใช้สตริงแบบ C ซึ่งสำรองไบต์เป็นค่าว่างสำหรับเทอร์มิเนเตอร์ ดังนั้นคุณต้องเขียนสคริปต์ของคุณอีกครั้งเพื่อให้ไพพ์ลำดับที่มีค่า null ว่างโดยไม่ต้องใช้ 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) จะได้รับเป็นอาร์กิวเมนต์แรกคือพา ธ ไปยังไพพ์นั้นซึ่งจะเปิดและอ่านเกือบจะเหมือนกับไฟล์ใด ๆ คุณสามารถอ่านเพิ่มเติมได้ที่นี่: /unix//a/17117/136742commandhd


1
ในขณะที่ถูกต้องนี่เป็นรายละเอียดการใช้งานและไม่ใช่เหตุผลที่แน่นอน ฉันดูแล้วมาตรฐาน POSIX ต้องการพฤติกรรมนี้จริง ๆ แล้วคุณก็มีเหตุผลที่แท้จริง (ตามที่บางคนชี้ให้เห็นzshจะทำ แต่เฉพาะในโหมดnōn-POSIX) จริง ๆ แล้วฉันค้นหาเพราะฉันสงสัยว่ามันคุ้มค่าที่จะใช้สิ่งนี้ในmksh...
mirabilos

@ mirabilos คุณจะสนใจที่จะขยายหรือไม่ AFAICT พฤติกรรมคือไม่ได้ระบุต่อ POSIX เพื่อทดแทนคำสั่งเมื่อการส่งออกมีอักขระ NUL และสำหรับ zsh ในโหมด POSIX ความแตกต่างที่เกี่ยวข้องเท่านั้นที่ฉันสามารถคิดก็คือว่าในshการจำลองไม่ได้อยู่ในค่าเริ่มต้นของ\0 ยังคงใช้ได้ในการจำลองระบบ $IFSecho "$(printf 'a\0b')"shzsh
Stéphane Chazelas

3
@ mirabilos เมื่อพิจารณาว่าเชลล์มีมาก่อนมาตรฐาน POSIX ในทศวรรษหรือมากกว่านั้นฉันเดาว่าคุณจะพบว่าเหตุผลที่แท้จริงคือเชลล์ใช้สตริง C-style และมาตรฐานนั้นถูกสร้างขึ้นมา
giusti

ฉันพบคำถามที่ดีสำหรับการสนทนาอย่างละเอียดเกี่ยวกับ printf กับ echo unix.stackexchange.com/questions/65803/…
Paulb

8

คุณสามารถใช้zshแทนซึ่งเป็นเชลล์เดียวที่สามารถเก็บอักขระ NUL ในตัวแปร ตัวละครที่ว่าแม้จะเกิดขึ้นในค่าเริ่มต้นของใน$IFSzsh

nul=$'\0'

หรือ:

nul=$'\x0'

หรือ

nul=$'\u0000'

หรือ

nul=$(printf '\0')

อย่างไรก็ตามโปรดทราบว่าคุณไม่สามารถส่งผ่านตัวแปรเช่นอาร์กิวเมนต์หรือตัวแปรสภาพแวดล้อมไปยังคำสั่งที่ดำเนินการเนื่องจากอาร์กิวเมนต์และตัวแปรสภาพแวดล้อมเป็นสตริงที่คั่นด้วย NUL ที่ส่งผ่านไปยังการexecve()เรียกระบบ (ข้อ จำกัด ของ API ของระบบไม่ใช่เชลล์ ) ในzshอย่างไรก็ตามคุณสามารถส่งผ่าน NUL ไบต์เป็นอาร์กิวเมนต์ไปยังฟังก์ชันหรือคำสั่งในตัว

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

1
คุณสามารถใช้ zsh แทนได้ ". ไม่เป็นไร - ฉันกำลังสอนตัวเองเรื่อง bash-scripting ในฐานะผู้เริ่มต้น ฉันไม่ต้องการสับสนกับไวยากรณ์อื่น แต่ขอบคุณ veray มากสำหรับการแนะนำ
Frank

ตามจริงแล้วคุณใช้zshไวยากรณ์ในคำถามของคุณ echo -n $headerเพื่อหมายถึงการส่งเนื้อหาของ$headerตัวแปรเป็นอาร์กิวเมนต์สุดท้ายเพื่อecho -nเป็นzsh( fishหรือrcหรือes) ไวยากรณ์ไม่ใช่bash ไวยากรณ์ ในbashที่มีความหมายที่แตกต่างกันมาก โดยทั่วไปแล้วzshจะเป็นเช่นksh( bash, GNU shell, เป็นส่วนหนึ่งของโคลนksh, Unix de-facto shell) แต่ด้วยการออกแบบที่แปลกที่สุดของ Bourne shell ได้รับการแก้ไข (และคุณสมบัติพิเศษมากมาย, และอีกมากมาย เป็นมิตรกับผู้ใช้มากขึ้น / น่าอัศจรรย์น้อยลง)
Stéphane Chazelas

ระวัง: zsh อาจเปลี่ยนศูนย์ไบต์ในบางครั้ง: echo $(printf 'ab\0cd') | od -vAn -tx1c พิมพ์ '61 62 20 63 64 0a` นั่นคือช่องว่างที่ควรมี NUL
Isaac

1
และนั่นคือสิ่งที่เปลือกหอยอื่น ๆ (ไม่มีไม่มี) จะทำซ้ำ ที่ทำให้สคริปต์ทำงานในรูปแบบที่พิเศษมากใน zsh ในความคิดของฉัน: zsh เพียงพยายามที่จะฉลาดเกินไป
Isaac

2
มี "แก้ไข" การออกแบบที่ผิดพลาดอยู่ในมาตรฐาน POSIX sh ที่คุ้นเคยกับการเขียนสคริปต์ zsh หมายความว่ามีใครคุ้นเคยกับการปฏิบัติซึ่งจะบั๊กถ้าใช้ในเชลล์อื่น ๆ นี่ไม่ใช่ปัญหาเกี่ยวกับไวยากรณ์ที่แตกต่างจากภาษาอื่นที่ทักษะหรือนิสัยไม่น่าจะถ่ายโอน แต่ไม่ใช่ในมือ
ชาร์ลส์ดัฟฟี่
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.