In Bash, quando si specificano gli argomenti della riga di comando per un comando, quali caratteri devono essere sottoposti a escape?
Sono limitato ai metacaratteri di Bash: spazio, tab,
|
, &
, ;
, (
, )
, <
, e >
?
In Bash, quando si specificano gli argomenti della riga di comando per un comando, quali caratteri devono essere sottoposti a escape?
Sono limitato ai metacaratteri di Bash: spazio, tab,
|
, &
, ;
, (
, )
, <
, e >
?
Risposte:
I seguenti caratteri hanno un significato speciale per la shell stessa in alcuni contesti e potrebbe essere necessario sfuggire agli argomenti:
`
Backtick (U + 0060 Grave Accent)~
Tilde (U + 007E)!
Punto esclamativo (U + 0021)#
Hash (segno numero U + 0023)$
Simbolo del dollaro (U + 0024)&
E commerciale (U + 0026)*
Asterisco (U + 002A)(
Parentesi sinistra (U + 0028))
Parentesi destra (U + 0029)
( ⇥
) Scheda (U + 0009){
Parentesi graffa sinistra (U + 007B Parentesi graffa sinistra)[
Staffa quadrata sinistra (U + 005B)|
Barra verticale (linea verticale U + 007C)\
Barra rovesciata (Solido inverso U + 005C);
Punto e virgola (U + 003B)'
Virgoletta singola / Apostrofo (U + 0027)"
Doppia citazione (U + 0022)↩
Nuova linea (U + 000A)<
Meno di (U + 003C)>
Maggiore di (U + 003E)?
Punto interrogativo (U + 003F)
Spazio (U + 0020) 1Alcuni di questi personaggi sono usati per più cose e in più posti di quello che ho collegato.
Esistono alcuni casi angolari esplicitamente facoltativi:
!
può essere disabilitato con set +H
, che è l'impostazione predefinita nelle shell non interattive.{
può essere disabilitato con set +B
.*
e ?
può essere disabilitato con set -f
oset -o noglob
.=
Anche il segno di uguale (U + 003D) deve essere evitato se set -k
oset -o keyword
è abilitato.Per uscire da una nuova riga è necessario un preventivo : le barre rovesciate non funzionano. Qualsiasi altro personaggio elencato in IFS avrà bisogno di una gestione simile. Non è necessario per fuggire ]
o }
, ma non ha bisogno di fuggire )
perché è un operatore.
Alcuni di questi personaggi hanno limiti più severi quando hanno davvero bisogno di fuggire rispetto ad altri. Ad esempio, a#b
va bene, ma a #b
è un commento, mentre >
dovrebbe essere evaso in entrambi i contesti. Non fa male sfuggirle tutte in modo conservativo, ed è più facile che ricordare le sottili distinzioni.
Se il nome del comando è di per sé una parola chiave shell ( if
, for
, do
) allora avrete bisogno di fuggire o citare troppo. L'unico interessante di questi è in
, perché non è ovvio che è sempre una parola chiave. Non è necessario farlo per le parole chiave utilizzate negli argomenti, solo quando hai (stupidamente!) Nominato un comando dopo uno di essi. Gli operatori Shell ( (
, &
ecc.) Devono sempre quotare ovunque si trovino.
1 Stéphane ha notato che anche qualsiasi altro carattere vuoto a byte singolo della tua locale deve essere evaso. Nei locali più comuni e sensibili, almeno quelli basati su C o UTF-8, sono solo i caratteri bianchi sopra. In alcuni locali ISO-8859-1, lo spazio no-break U + 00A0 è considerato vuoto, inclusi Solaris, i BSD e OS X (penso in modo errato). Se hai a che fare con un locale sconosciuto arbitrario, potrebbe includere qualsiasi cosa, comprese le lettere, quindi buona fortuna.
Concepibilmente, un singolo byte considerato vuoto potrebbe apparire all'interno di un carattere multi-byte che non era vuoto e non avresti modo di sfuggire a questo se non di mettere il tutto tra virgolette. Questa non è una preoccupazione teorica: in una locale ISO-8859-1 dall'alto, quel A0
byte che è considerato uno spazio vuoto può apparire all'interno di caratteri multibyte come UTF-8 codificato "à" ( C3 A0
). Per gestire quei personaggi in modo sicuro dovresti citarli "à"
. Questo comportamento dipende dalla configurazione locale nell'ambiente che esegue lo script, non da quello in cui è stato scritto.
Penso che questo comportamento sia rotto in molti modi, ma dobbiamo giocare la mano che ci viene data. Se stai lavorando con un set di caratteri multibyte non auto-sincronizzante, la cosa più sicura sarebbe quella di citare tutto. Se sei in UTF-8 o C, sei al sicuro (per il momento).
!
quando è abilitata l'espansione della cronologia csh, in genere non negli script. [ ! -f a ]
o find . ! -name...
stanno bene. Questo è coperto dalla sezione dei limiti più stretti, ma forse vale la pena menzionarlo esplicitamente.
hash[foo"]"]=
, ${var-foo"}"}
, [[ "!" = b ]]
, [[ a = "]]" ]]
, gli operatori regexp per [[ x =~ ".+[" ]]
. Altre parole chiave di {
( if
, while
, for
...) avrebbe bisogno di essere citato in modo che non stanno riconosciuti come tali ...
]
), quindi non li sto elencando. Non credo che nessuna parola chiave debba essere citata nella posizione dell'argomento.
In GNU Parallel questo è testato e ampiamente utilizzato:
$a =~ s/[\002-\011\013-\032\\\#\?\`\(\)\{\}\[\]\^\*\<\=\>\~\|\; \"\!\$\&\'\202-\377]/\\$&/go;
# quote newline as '\n'
$a =~ s/[\n]/'\n'/go;
E 'testato in bash
, dash
, ash
, ksh
, zsh
, e fish
. Alcuni caratteri non devono essere citati in alcune (versioni) delle shell, ma quanto sopra funziona in tutte le shell testate.
Se vuoi semplicemente citare una stringa, puoi reindirizzarla in parallel --shellquote
:
printf "&*\t*!" | parallel --shellquote
Per la soluzione di fuga leggera in Perl, sto seguendo il principio delle virgolette singole. Una stringa di Bash tra virgolette singole può avere qualsiasi carattere, tranne la virgoletta singola stessa.
Il mio codice:
my $bash_reserved_characters_re = qr([ !"#$&'()*;<>?\[\\`{|~\t\n]);
while(<>) {
if (/$bash_reserved_characters_re/) {
my $quoted = s/'/'"'"'/gr;
print "'$quoted'";
} else {
print $_;
}
}
Esempio di esecuzione 1:
$ echo -n "abc" | perl escape_bash_special_chars.pl
abc
Esempio di esecuzione 2:
echo "abc" | perl escape_bash_special_chars.pl
'abc
'
Esempio di esecuzione 3:
echo -n 'ab^c' | perl escape_bash_special_chars.pl
ab^c
Esempio di esecuzione 4:
echo -n 'ab~c' | perl escape_bash_special_chars.pl
'ab~c'
Esempio di esecuzione 5:
echo -n "ab'c" | perl escape_bash_special_chars.pl
'ab'"'"'c'
echo 'ab'"'"'c'
ab'c