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/…