bash non può memorizzare valori esadecimali 0x00 in variabili


11

Sto cercando di fare alcuni trucchi con dd. Ho pensato che sarebbe stato possibile memorizzare alcuni esagoni in una variabile chiamata "header" per reindirizzarlo in dd.

Il mio primo passo senza una variabile è stato questo:

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

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

Dopo ciò ho provato questo:

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

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

Come puoi vedere, ho perso il mio \x00valore nella $headervariabile. Qualcuno ha una spiegazione per questo comportamento? Questo mi sta facendo impazzire.


Ho capito bash: warning: command substitution: ignored null byte in input.
Kusalananda

Mancano le virgolette, header="$(echo -ne "\x36\xc9\xda\x00\xb4")"; echo -n "$header" | hdtuttavia dovrebbe essere solo questo a dare lo stesso risultato.
ctrl-alt-delor,

Funziona header="\x36\xc9\xda\x00\xb4"; echo -n "$header" | hd, ma non è la stessa cosa che sta memorizzando la forma leggibile dall'uomo.
ctrl-alt-delor,

Risposte:


16

Non è possibile memorizzare un byte null in una stringa perché Bash utilizza stringhe in stile C, che riservano il byte null ai terminatori. Quindi è necessario riscrivere lo script per reindirizzare semplicemente la sequenza che contiene il byte null senza che Bash debba memorizzarlo nel mezzo. Ad esempio, puoi farlo:

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

Si noti, a proposito, che non è necessario echo; puoi usare Bash printfper molte altre semplici attività.

O invece di concatenare, è possibile utilizzare un file temporaneo:

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

Naturalmente, questo ha il problema che il file /tmp/mysequencepotrebbe già esistere. E ora devi continuare a creare file temporanei e salvarne i percorsi in stringhe.

Oppure puoi evitarlo usando la sostituzione del processo:

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

L' <(command)operatore crea una pipe denominata nel file system, che riceverà l'output di command. hdriceverà, come primo argomento, il percorso di quella pipe, che aprirà e leggerà quasi come qualsiasi file. Puoi leggere di più qui: /unix//a/17117/136742 .


1
Sebbene corretto, questo è un dettaglio di implementazione e non il motivo esatto. L'ho guardato e lo standard POSIX in realtà richiede questo comportamento, quindi hai il vero motivo. (Come alcuni hanno sottolineato, zshlo faranno, ma solo in modalità nōn-POSIX.) In realtà l'ho esaminato perché mi chiedevo se valesse la pena implementarlo in mksh...
mirabilos,

@mirabilos, ti andrebbe di approfondire? AFAICT, il comportamento non è specificato per POSIX per la sostituzione dei comandi quando l'output ha caratteri NUL, e per zsh in modalità POSIX, l'unica differenza rilevante che posso pensare è che shnell'emulazione, \0non è nel valore predefinito di $IFS. echo "$(printf 'a\0b')"funziona ancora bene shnell'emulazione in zsh.
Stéphane Chazelas,

3
@mirabilos Considerando che le shell precedono lo standard POSIX di un decennio o più, immagino che potresti scoprire che il vero motivo reale è che le shell hanno usato stringhe in stile C e lo standard è stato costruito attorno a quello.
giusti,

Ho trovato un buon Q per una discussione dettagliata su printf contro echo. unix.stackexchange.com/questions/65803/…
Paulb

8

È possibile utilizzare zshinvece quale è l'unica shell in grado di memorizzare il carattere NUL nelle sue variabili. Quel personaggio si trova addirittura nel valore predefinito di $IFSin zsh.

nul=$'\0'

O:

nul=$'\x0'

O

nul=$'\u0000'

O

nul=$(printf '\0')

Tuttavia, non è possibile passare una variabile come argomento o variabile d'ambiente a un comando che viene eseguito poiché gli argomenti e le variabili di ambiente sono stringhe delimitate da NUL passate alla execve()chiamata di sistema (una limitazione dell'API del sistema, non della shell ). In zsh, tuttavia, è possibile passare byte NUL come argomenti a funzioni o comandi incorporati.

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

1
"Puoi usare zsh invece". No grazie - Sto insegnando a me stesso bash-scripting come principiante in questo momento. Non voglio confondermi con un'altra sintassi. Ma grazie mille per averlo suggerito
Frank

È un dato di fatto, hai usato la zshsintassi nella tua domanda. echo -n $headersignificare passare il contenuto della $headervariabile come ultimo argomento echo -nè zsh(o fisho rco es) sintassi, non bash sintassi. In bash, questo ha un significato molto diverso . Più in generale zshè come ksh( bashla shell GNU, essendo più o meno un clone parziale della kshshell di fatto Unix) ma con la maggior parte delle idiosincrasie progettuali della shell Bourne fisse (e molte funzionalità extra, e molte più user-friendly / meno sorprendente).
Stéphane Chazelas,

Fai attenzione: a volte zsh può cambiare un byte zero: echo $(printf 'ab\0cd') | od -vAn -tx1c stampa `61 62 20 63 64 0a`, che è uno spazio in cui dovrebbe esistere un NUL.
Isaac,

1
E questo è qualcosa che nessun'altra (nessuna, nessuna) shell si riprodurrà. Questo fa sì che uno script si comporti in modi molto speciali in zsh. Secondo me: zsh sta solo cercando di essere troppo intelligente.
Isaac,

2
Avere "risolto" i malfunzionamenti del design presenti nello standard sh POSIX che abituarsi a scrivere script zsh significa che ci si sta abituando a pratiche che potrebbero essere errate se esercitate in qualsiasi altra shell. Questo non è un problema con una sintassi così diversa da un linguaggio diverso che le abilità o le abitudini non sono suscettibili di trasferimento, ma non è così per il caso.
Charles Duffy,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.