bash tidak dapat menyimpan hexvalue 0x00 dalam variabel

11

Saya mencoba melakukan beberapa trik dengan dd. Saya pikir akan mungkin untuk menyimpan beberapa nilai hexa dalam variabel yang disebut "header" untuk menyalurkannya ke dd.

Langkah pertama saya tanpa variabel adalah ini:

$ echo -ne "\x36\xc9\xda\x00\xb4" |dd of=hex
$ hd hex

00000000  36 c9 da 00 b4                                    |6....|
00000005

Setelah itu saya coba ini:

$ header=$(echo -ne "\x36\xc9\xda\x00\xb4") 
$ echo -n $header | hd

00000000  36 c9 da b4                                       |6...|
00000004

Seperti yang Anda lihat, saya kehilangan \x00nilai saya dalam $headervariabel. Adakah yang punya penjelasan untuk perilaku ini? Ini membuatku gila.

jujur
sumber
Saya mengerti bash: warning: command substitution: ignored null byte in input.
Kusalananda
Anda melewatkan penawaran, header="$(echo -ne "\x36\xc9\xda\x00\xb4")"; echo -n "$header" | hdnamun ini hanya memberikan hasil yang sama.
ctrl-alt-delor
Ini berfungsi header="\x36\xc9\xda\x00\xb4"; echo -n "$header" | hd, tetapi tidak sama dengan menyimpan bentuk yang dapat dibaca manusia.
ctrl-alt-delor

Jawaban:

16

Anda tidak dapat menyimpan byte nol dalam string karena Bash menggunakan string gaya-C, yang menyimpan byte null untuk terminator. Jadi, Anda perlu menulis ulang skrip Anda untuk hanya mem-pipe urutan yang berisi byte nol tanpa Bash perlu menyimpannya di tengah. Misalnya, Anda dapat melakukan ini:

printf "\x36\xc9\xda\x00\xb4" | hd

Perhatikan, omong-omong, bahwa Anda tidak perlu echo; Anda dapat menggunakan Bash printfuntuk ini banyak tugas sederhana lainnya.

Atau alih-alih merantai, Anda dapat menggunakan file sementara:

printf "\x36\xc9\xda\x00\xb4" > /tmp/mysequence
hd /tmp/mysequence

Tentu saja, ini memiliki masalah bahwa file tersebut /tmp/mysequencemungkin sudah ada. Dan sekarang Anda harus terus membuat file sementara dan menyimpan path mereka dalam string.

Atau Anda dapat menghindarinya dengan menggunakan proses substitusi:

hd <(printf "\x36\xc9\xda\x00\xb4")

The <(command)Operator menciptakan pipa bernama dalam sistem file, yang akan menerima output dari command. hdakan menerima, sebagai argumen pertamanya, jalur ke pipa itu — yang akan dibuka dan dibaca hampir seperti file apa pun. Anda dapat membaca lebih lanjut tentang ini di sini: /unix//a/17117/136742 .

giusti
sumber
1
Meskipun benar, ini adalah detail implementasi dan bukan alasan yang tepat. Saya melihatnya, dan standar POSIX sebenarnya membutuhkan perilaku ini, jadi Anda punya alasan sebenarnya . (Seperti yang telah ditunjukkan beberapa orang, zshakan melakukannya, tetapi hanya dalam mode nōn-POSIX.) Saya benar-benar melihatnya karena saya bertanya-tanya apakah layak untuk menerapkan ini di mksh...
mirabilos
@mirabilos, maukah Anda memperluas itu? AFAICT, perilaku tidak ditentukan per POSIX untuk substitusi perintah ketika output memiliki karakter NUL, dan untuk zsh dalam mode POSIX, satu-satunya perbedaan yang relevan yang dapat saya pikirkan adalah bahwa dalam shemulasi, \0tidak dalam nilai default $IFS. echo "$(printf 'a\0b')"masih berfungsi OK dalam shpersaingan dalam zsh.
Stéphane Chazelas
3
@mirabilos Menimbang bahwa kerang mendahului standar POSIX oleh satu dekade atau lebih, saya kira Anda bisa mengetahui bahwa alasan sebenarnya adalah kerang menggunakan string gaya-C dan standar dibangun di sekitar itu.
giusti
Saya menemukan Q yang bagus untuk diskusi terperinci tentang printf versus echo. unix.stackexchange.com/questions/65803/…
Paulb
8

Anda bisa menggunakan zshyang merupakan satu-satunya shell yang dapat menyimpan karakter NUL dalam variabel-variabelnya. Karakter itu bahkan ada dalam nilai default $IFSin zsh.

nul=$'\0'

Atau:

nul=$'\x0'

Atau

nul=$'\u0000'

Atau

nul=$(printf '\0')

Namun perhatikan bahwa Anda tidak dapat meneruskan variabel seperti argumen atau variabel lingkungan ke perintah yang dieksekusi karena variabel argumen dan lingkungan adalah string yang dibatasi NUL yang diteruskan ke execve()panggilan sistem (batasan API sistem, bukan shell ). Dalam zsh, namun Anda dapat lulus NUL byte sebagai argumen untuk fungsi atau builtin perintah.

echo $'\0' # works
/bin/echo $'\0' # doesn't
Stéphane Chazelas
sumber
1
"Kamu bisa menggunakan zsh sebagai gantinya". Tidak, terima kasih - Saya sedang belajar bash-scripting sebagai pemula saat ini. Saya tidak ingin membingungkan diri saya dengan sintaks lain. Tapi terima kasih banyak atas sarannya
Frank
Faktanya, Anda menggunakan zshsintaks dalam pertanyaan Anda. echo -n $headerberarti melewatkan konten $headervariabel sebagai argumen terakhir echo -nadalah zsh( fishatau rcatau es) sintaks, bukan bash sintaks. Dalam bash, itu memiliki arti yang sangat berbeda . Lebih umum zshseperti ksh( bash, shell GNU, yang kurang lebih merupakan bagian-klon dari ksh, shell Unix de-facto) tetapi dengan sebagian besar keanehan desain dari shell Bourne yang diperbaiki (dan banyak fitur tambahan, dan banyak lebih user-friendly / kurang mencengangkan).
Stéphane Chazelas
Hati-hati: zsh kadang-kadang dapat mengubah byte nol: echo $(printf 'ab\0cd') | od -vAn -tx1c mencetak `61 62 20 63 64 0a`, itu adalah ruang di mana NUL seharusnya ada.
Isaac
1
Dan itu adalah sesuatu yang tidak akan direproduksi oleh shell lain (tidak ada, nihil). Itu membuat skrip berperilaku dengan cara yang sangat khusus di zsh. Menurut pendapat saya: zsh hanya mencoba untuk menjadi terlalu pintar.
Isaac
2
Setelah "memperbaiki" kesalahan desain yang ada dalam standar sh POSIX bahwa membiasakan diri menulis skrip zsh berarti seseorang menjadi terbiasa dengan praktik yang akan menjadi buggy jika dilakukan di shell lain. Ini bukan masalah dengan sintaksis yang sangat berbeda dengan bahasa yang berbeda sehingga keterampilan atau kebiasaan tidak mungkin untuk ditransfer, tetapi tidak demikian halnya.
Charles Duffy