2013-10-07 17 views
15

consente l'espansione $'string'. La mia man bash dice:

Parole del modulo $'string' vengono trattati in modo speciale. La parola si espande in string, con caratteri di escape rovesciato sostituiti come specificato dallo standard ANSI C. Backslash sequenze di escape, se presenti, vengono decodificati come segue:
\a avviso (campana)
\b backspace
\e
\E un carattere di escape
\f avanzamento forma
\n nuova linea
\r ritorno carrello
\t scheda orizzontale
\v scheda verticale
\ rovesciato
\' apostrofo
\" doppio apice
\nnn il carattere a otto bit il cui valore è il valore ottale nnn (una a tre cifre)
\xHH il carattere a otto bit il cui valore è il valore esadecimale HH (una o due cifre esadecimali)
\cx un controllo- x carattere

Il risultato è esteso tra apici singoli, come se il simbolo del dollaro non era stato presente.

Ma Perché non convertire $'\0' e $'\x0' in un carattere null?
È documentato? C'è una ragione? (Si tratta di una funzione o di una limitazione o addirittura un bug?)

$ hexdump -c <<< _$'\0'$'\x1\x2\x3\x4_' 
0000000 _ 001 002 003 004 _ \n 
0000007 

echo dà il risultato atteso:

> hexdump -c < <(echo -e '_\x0\x1\x2\x3_') 
0000000 _ \0 001 002 003 _ \n 
0000007 

La mia versione bash

$ bash --version | head -n 1 
GNU bash, version 4.1.2(1)-release (x86_64-redhat-linux-gnu) 

Perché echo $'foo\0bar' non si comporta come echo -e 'foo\0bar'?

+3

Bella domanda! Forse è una cosa Posix? In bocca al lupo. – shellter

+0

Grazie per tutte le risposte. Ho avuto lo stesso problema durante l'utilizzo di netcat per testare l'interfaccia SGCI su un server. L'intestazione SCGI ha caratteri NUL. Dopo aver letto qui, specialmente il suggerimento di usare i tubi, ho sviluppato una soluzione alternativa. Io uso l'ottale 377 (ASCII 255) dove devono essere i caratteri NUL, quindi canalizzo la stringa attraverso tr prima di collegarla a netcat xmlreq = ' system.client_version 'scgihdr = CONTENT_LENGTH $' \ 377 '$ {# xmlreq} $' \ 377'SCGI $ '\ 377'1 $' \ 377' echo -n $ {# scgihdr –

risposta

20

È un limite. bash non consente ai valori stringa di contenere byte NUL interni.

Le stringhe di caratteri Posix (e C) non possono contenere NUL interni. Vedere, per esempio, la Posix definition di stringa di caratteri (corsivo):

3,92 stringa di caratteri

Una sequenza contigua di caratteri terminati da e comprendente il primo nullo byte.

Analogamente, C standard è ragionevolmente esplicito sul carattere NUL in stringhe di caratteri:

§ 5.2.1p2 & hellip; Un byte con tutti i bit impostati a 0, chiamato il carattere nullo, sussiste nei il set di caratteri di esecuzione di base; è utilizzato per terminare una stringa di caratteri.

Posix proibisce esplicitamente l'uso di NUL (e /) nei nomi (XBD 3.170) o variabili di ambiente (XBD 8.1 "... sono considerati per terminare con un byte nullo."

In questo contesto, i linguaggi di comando della shell, compresa la bash, tendono ad utilizzare la stessa definizione di una stringa di caratteri, come una sequenza di caratteri non NUL terminati da un singolo NUL.

È possibile passare NUL liberamente tramite pipe bash, ovviamente, e nulla ti impedisce di assegnare una variabile di shell all'output di un programma che emette un byte NUL. Tuttavia, le conseguenze sono "non specificate" ac con Posix (XSH 2.6.3 "Se l'output contiene byte null, il comportamento non è specificato."). In bash, i NUL vengono rimossi, a meno che non si inserisca un NUL in una stringa usando la sintassi C-escape di bash ($'\0'), nel qual caso il NUL finirà per terminare il valore.

Su una nota pratica, considerare la differenza tra i due seguenti modi di tentare di inserire un NUL nel stdin di un programma di utilità:

$ # Prefer printf to echo -n 
$ printf $'foo\0bar' | wc -c 
3 
$ printf 'foo\0bar' | wc -c 
7 
$ # Bash extension which is better for strings which might contain % 
$ printf %b 'foo\0bar' | wc -c 
7 
+1

Grande informazioni. Ri: "niente ti impedisce di assegnare una variabile di shell all'output di un programma che emette un NUL" - vale la pena notare che il valore della variabile sarà sempre tagliato al primo NUL rilevato. "Se si inserisce un NUL in una stringa utilizzando una delle sequenze di escape barra rovesciata di bash ($ '\ 0'), finirà per terminare il valore." - per chiarire: l'inserimento di '$ '\ 0'' nella stringa _another_ non terminerà la stringa generale, ma semplicemente ignorerà' $' \ 0''; ad esempio, 'a $ '\ 0'b' ->' ab'; a '\ 0' _inside_' $ '...' ', tuttavia, _will_ taglia fuori quella stringa; ad esempio, '$ 'a \ 0b'' ->' a'. – mklement0

+1

@ mklement0: Sì, ho sbagliato che due anni fa. Grazie. Risolto, ora, credo. – rici

+0

Grazie per l'aggiornamento. Assegnazione dell'output del comando a una variabile: Dato che i valori delle variabili 'bash' sono memorizzati internamente come stringhe C, non possono mai contenere NUL. Tuttavia, vale la pena distinguere tra (a) 'var = $ (...)', nel qual caso, come si afferma, tutti i NUL sono semplicemente _stripped_, quindi il valore che viene assegnato per definizione non contiene mai NUL ma contiene tutti gli altri caratteri , e (b) 'read -rd '' var <<(....)', dove l'input può contenere NUL, ma 'read' non consente la lettura oltre il primo NUL e il valore è quindi _cut off_ at il primo NUL. – mklement0

3

È un carattere nullo, ma dipende da cosa intendi.

Il carattere null rappresenta una stringa vuota, che è ciò che si ottiene quando la si espande. È un caso speciale e penso che sia implicito dalla documentazione ma non effettivamente dichiarato.

In C binario zero '\0' termina una stringa e rappresenta anche una stringa vuota. Bash è scritto in C, quindi probabilmente ne consegue.

Modifica: POSIX menziona una stringa nulla in un numero di punti. In "definizioni Base" si definisce una stringa vuota come:

3,146 stringa vuota (o stringa Null)
Una stringa il cui primo byte è un byte nullo.

5

Ma perché bash non converte $'\0' e $'\x0' in un carattere null?

Perché un carattere null termina una stringa.

$ echo $'hey\0you' 
hey 
Problemi correlati