Bash ใช้สตริง C-style ภายในซึ่งจะถูกยกเลิกด้วยไบต์ null ซึ่งหมายความว่าสตริง Bash (เช่นค่าของตัวแปรหรืออาร์กิวเมนต์ของคำสั่ง) ไม่สามารถมีค่าเป็น null จริง ๆ ตัวอย่างเช่นมินิสคริปต์นี้:
foobar=$'foo\0bar' # foobar='foo' + null byte + 'bar'
echo "${#foobar}" # print length of $foobar
จริง ๆ แล้วพิมพ์3เพราะ$foobarเป็นเพียงแค่'foo': barมาหลังจากจุดสิ้นสุดของสตริง
ในทำนองเดียวกันecho $'foo\0bar'เพียงพิมพ์fooเพราะechoไม่รู้เกี่ยวกับชิ้น\0barส่วน
อย่างที่คุณเห็น\0ลำดับนั้นเป็นจริงทำให้เข้าใจผิดมากใน$'...'สตริงสไตล์ ดูเหมือนว่าเป็น null ภายในสตริง แต่มันก็ไม่ได้ทำงานอย่างนั้น ในตัวอย่างแรกของคุณ, คุณคำสั่งมีread -d $'\0'ใช้งานได้ แต่เพียงเพราะ-d ''ยังใช้งานได้! (นั่นไม่ใช่คุณลักษณะที่มีการบันทึกไว้อย่างชัดเจนreadแต่ฉันคิดว่ามันใช้งานได้ด้วยเหตุผลเดียวกัน: ''เป็นสตริงว่างดังนั้นไบต์ null ที่ยุติลงจะมาทันทีมีการบันทึกไว้โดยใช้ "อักขระตัวแรกของdelim " และฉันเดาว่าแม้จะใช้งานได้ ถ้า "อักขระตัวแรก" ผ่านจุดสิ้นสุดของสตริง!)-d delim
แต่ดังที่คุณทราบจากfindตัวอย่างของคุณอาจเป็นไปได้ที่คำสั่งพิมพ์ไบต์ว่างและสำหรับไบต์นั้นจะถูกไพพ์ไปยังคำสั่งอื่นที่อ่านว่าเป็นอินพุต ส่วนหนึ่งของที่อาศัยการจัดเก็บไบต์โมฆะในสตริงภายในทุบตี ปัญหาเดียวของตัวอย่างที่สองของคุณคือเราไม่สามารถใช้$'\0'อาร์กิวเมนต์ในคำสั่งได้ echo "$file"$'\0'สามารถพิมพ์ไบต์ว่างได้อย่างมีความสุขในตอนท้ายถ้าเพียงรู้ว่าคุณต้องการ
ดังนั้นแทนที่จะใช้echoคุณสามารถใช้printfซึ่งสนับสนุนประเภทเดียวกันของลำดับหนีเป็น$'...'สตริงสไตล์ ด้วยวิธีนี้คุณสามารถพิมพ์ null โดยไม่ต้องมี null null ภายในสตริง ที่จะมีลักษณะเช่นนี้:
for file in * ; do printf '%s\0' "$file" ; done \
| while IFS= read -r -d '' ; do echo "$REPLY" ; done
หรือเพียงแค่นี้:
printf '%s\0' * \
| while IFS= read -r -d '' ; do echo "$REPLY" ; done
(หมายเหตุ: echoจริง ๆ แล้วยังมีการ-eตั้งค่าสถานะที่จะให้มันประมวลผล\0และพิมพ์ไบต์ที่ว่างเปล่า แต่จากนั้นก็จะพยายามประมวลผลลำดับพิเศษใด ๆ ในชื่อไฟล์ของคุณดังนั้นprintfวิธีนี้จึงแข็งแกร่งกว่า)
อนึ่งมีเปลือกบางอย่างที่จะช่วยให้ null ไบต์สตริงภายใน ตัวอย่างของคุณใช้งานได้ดีใน Zsh เช่น (สมมติว่าการตั้งค่าเริ่มต้น) อย่างไรก็ตามไม่ว่าเชลล์ของคุณระบบปฏิบัติการแบบ Unix จะไม่มีวิธีการรวมไบต์ว่างในอาร์กิวเมนต์ของโปรแกรม (เนื่องจากข้อโต้แย้งของโปรแกรมถูกส่งเป็นสตริง C-style) ดังนั้นจะมีข้อ จำกัด อยู่เสมอ (ตัวอย่างเช่นคุณสามารถทำงานใน zsh เพียงเพราะechoเป็น builtin เปลือกดังนั้น zsh สามารถเรียกมันโดยไม่ต้องอาศัยการสนับสนุนระบบปฏิบัติการสำหรับการเรียกโปรแกรมอื่น ๆ . ถ้าคุณใช้command echoแทนechoเพื่อที่จะข้าม builtin และใช้แบบสแตนด์อโลนechoโปรแกรมบน$PATH, คุณจะเห็นพฤติกรรมแบบเดียวกันใน Zsh เหมือนกับใน Bash)
-d ''มีการกำหนดขอบเขตไว้แล้ว\0? ฉันพบคำอธิบายที่นี่: stackoverflow.com/questions/8677546/…