Bash menggunakan string C-style secara internal, yang diakhiri dengan byte nol. Ini berarti bahwa string Bash (seperti nilai variabel, atau argumen ke perintah) tidak pernah bisa benar-benar berisi byte nol. Misalnya, skrip mini ini:
foobar=$'foo\0bar' # foobar='foo' + null byte + 'bar'
echo "${#foobar}" # print length of $foobar
sebenarnya mencetak 3
, karena $foobar
sebenarnya hanya 'foo'
: bar
datang setelah akhir string.
Demikian pula, echo $'foo\0bar'
cetak saja foo
, karena echo
tidak tahu tentang \0bar
bagian itu.
Seperti yang Anda lihat, \0
urutannya sebenarnya sangat menyesatkan dalam $'...'
string-gaya; kelihatannya seperti byte nol di dalam string, tetapi tidak berakhir seperti itu. Dalam contoh pertama Anda, read
perintah Anda telah -d $'\0'
. Ini berhasil, tetapi hanya karena -d ''
juga berfungsi! (Itu bukan fitur yang didokumentasikan secara eksplisit read
, tapi saya kira itu bekerja untuk alasan yang sama: ''
adalah string kosong, jadi pengakhiran byte nolnya segera datang. Didokumentasikan sebagai menggunakan "Karakter pertama delim ", dan saya kira itu berfungsi jika "karakter pertama" melewati akhir string!)-d delim
Tetapi seperti yang Anda tahu dari find
contoh Anda , adalah mungkin untuk perintah untuk mencetak byte nol, dan untuk byte tersebut akan disalurkan ke perintah lain yang membacanya sebagai input. Tidak ada bagian yang bergantung pada penyimpanan byte nol dalam sebuah string di dalam Bash . Satu-satunya masalah dengan contoh kedua Anda adalah bahwa kami tidak dapat menggunakan $'\0'
argumen untuk suatu perintah; echo "$file"$'\0'
bisa dengan senang mencetak byte nol di bagian akhir, andai saja ia tahu Anda menginginkannya.
Jadi, alih-alih menggunakan echo
, Anda bisa menggunakan printf
, yang mendukung jenis pelarian yang sama seperti $'...'
string -style. Dengan begitu, Anda dapat mencetak byte nol tanpa harus memiliki byte nol di dalam sebuah string. Itu akan terlihat seperti ini:
for file in * ; do printf '%s\0' "$file" ; done \
| while IFS= read -r -d '' ; do echo "$REPLY" ; done
atau hanya ini:
printf '%s\0' * \
| while IFS= read -r -d '' ; do echo "$REPLY" ; done
(Catatan: echo
sebenarnya juga memiliki -e
flag yang akan membiarkannya memproses \0
dan mencetak byte nol; tetapi kemudian juga akan mencoba untuk memproses urutan khusus apa pun dalam nama file Anda. Jadi printf
pendekatannya lebih kuat.)
Kebetulan, ada beberapa kerang yang tidak memungkinkan null byte dalam string. Contoh Anda berfungsi dengan baik di Zsh, misalnya (dengan asumsi pengaturan default). Namun, terlepas dari cangkang Anda, sistem operasi mirip Unix tidak menyediakan cara untuk memasukkan null byte di dalam argumen ke program (karena argumen program dilewatkan sebagai string gaya-C), jadi selalu ada beberapa batasan. (Contoh Anda dapat bekerja di Zsh hanya karena echo
shell builtin, jadi Zsh dapat menjalankannya tanpa bergantung pada dukungan OS untuk menjalankan program lain. Jika Anda menggunakannya command echo
sebagai pengganti echo
, sehingga ia mem-by-pass builtin dan menggunakan echo
program mandiri pada $PATH
, Anda akan melihat perilaku yang sama di Zsh seperti di Bash.)
-d ''
sudah berarti membatasi\0
? Saya menemukan penjelasan di sini: stackoverflow.com/questions/8677546/…