Welche Zeichen müssen in Bash beim Angeben von Befehlszeilenargumenten für einen Befehl maskiert werden?
Sind sie auf die Metazeichen von Bash beschränkt: Leerzeichen, Tabulator
|
, &
, ;
, (
, )
, <
, und >
?
Welche Zeichen müssen in Bash beim Angeben von Befehlszeilenargumenten für einen Befehl maskiert werden?
Sind sie auf die Metazeichen von Bash beschränkt: Leerzeichen, Tabulator
|
, &
, ;
, (
, )
, <
, und >
?
Antworten:
Die folgenden Zeichen haben in einigen Kontexten eine besondere Bedeutung für die Shell selbst und müssen möglicherweise in Argumenten maskiert werden:
`
Backtick (U + 0060 Grabakzent )~
Tilde (U + 007E)!
Ausrufezeichen (U + 0021)#
Hash (U + 0023 Nummernzeichen)$
Dollarzeichen (U + 0024)&
Et-Zeichen (U + 0026)*
Sternchen (U + 002A)(
Linke Klammer (U + 0028))
Rechte Klammer (U + 0029)
( ⇥
) Tab (U + 0009){
Linke Klammer (U + 007B Linke geschweifte Klammer)[
Linke eckige Klammer (U + 005B)|
Vertikaler Balken (vertikale Linie U + 007C)\
Backslash (U + 005C umgekehrter Solidus);
Semikolon (U + 003B)'
Einfaches Anführungszeichen / Apostroph (U + 0027)"
Doppelte Anführungszeichen (U + 0022)↩
Neue Linie (U + 000A)<
Weniger als (U + 003C)>
Größer als (U + 003E)?
Fragezeichen (U + 003F)
Leertaste (U + 0020) 1Einige dieser Zeichen werden für mehr Dinge und an mehr Stellen als die von mir verknüpften verwendet.
Es gibt einige Eckfälle, die ausdrücklich optional sind:
!
kann mit deaktiviert werden set +H
, was die Standardeinstellung bei nicht interaktiven Shells ist.{
kann mit deaktiviert werden set +B
.*
und ?
kann mit set -f
oderset -o noglob
deaktiviert werden .=
Das Gleichheitszeichen (U + 003D) muss ebenfalls maskiert werden, wenn set -k
oderset -o keyword
aktiviert ist.Ein Zeilenumbruch muss in Anführungszeichen gesetzt werden - umgekehrte Schrägstriche reichen nicht aus. Alle anderen in IFS aufgelisteten Zeichen müssen ähnlich behandelt werden. Sie müssen nicht entkommen müssen ]
oder }
aber Sie tun müssen , entkommen )
ein Operator , weil es.
Einige dieser Charaktere haben strengere Grenzen, wann sie wirklich fliehen müssen als andere. Zum Beispiel a#b
ist in Ordnung, ist aber a #b
ein Kommentar, während >
in beiden Kontexten ein Escape erforderlich wäre. Es tut sowieso nicht weh, ihnen allen konservativ zu entkommen, und es ist einfacher, sich an die feinen Unterschiede zu erinnern.
Wenn Ihr Befehlsnamen selbst ein Shell - Schlüsselwort ist ( if
, for
, do
) , dann werden Sie brauchen , um es zu entkommen oder zu zitieren. Das einzig interessante ist in
, dass es sich nicht immer um ein Schlüsselwort handelt. Sie müssen das nicht für Schlüsselwörter tun, die in Argumenten verwendet werden, sondern nur, wenn Sie (dummerweise!) Einen Befehl nach einem von ihnen benannt haben. Shell-Operatoren ( (
, &
usw.) müssen immer und überall zitiert werden.
1 Stéphane hat bemerkt, dass jedes andere Einzelbyte- Leerzeichen in Ihrem Gebietsschema ebenfalls maskiert werden muss. In den meisten gängigen, vernünftigen Gebietsschemata, zumindest denen, die auf C oder UTF-8 basieren, sind es nur die oben genannten Leerzeichen. In einigen ISO-8859-1-Ländereinstellungen wird der unterbrechungsfreie Speicherplatz U + 00A0 als leer betrachtet, einschließlich Solaris, BSDs und OS X (ich denke falsch). Wenn es sich um ein beliebiges unbekanntes Gebietsschema handelt, kann es so gut wie alles enthalten, einschließlich Buchstaben, also viel Glück.
Es ist vorstellbar, dass ein einzelnes Byte, das als leer betrachtet wird, in einem Multi-Byte-Zeichen erscheint, das nicht leer ist, und Sie können sich dem nur entziehen, wenn Sie das Ganze in Anführungszeichen setzen. Dies ist kein theoretisches Problem: In einem ISO-8859-1-Gebietsschema von oben kann dieses A0
Byte, das als Leerzeichen betrachtet wird, in Multibyte-Zeichen wie UTF-8-codiert "à" ( C3 A0
) auftreten. Um mit diesen Zeichen sicher umzugehen, müssten Sie sie in Anführungszeichen setzen "à"
. Dieses Verhalten hängt von der Länderkonfiguration in der Umgebung ab, in der das Skript ausgeführt wird, und nicht von der Konfiguration, in der Sie es geschrieben haben.
Ich denke, dieses Verhalten ist in mehrfacher Hinsicht problematisch, aber wir müssen die Hand spielen, die wir bekommen. Wenn Sie mit einem nicht selbstsynchronisierenden Multibyte-Zeichensatz arbeiten, ist es am sichersten, alles in Anführungszeichen zu setzen. Wenn Sie sich in UTF-8 oder C befinden, sind Sie (im Moment) in Sicherheit.
!
wenn die Erweiterung des csh-Verlaufs aktiviert ist, normalerweise nicht in Skripten. [ ! -f a ]
oder find . ! -name...
sind in Ordnung. Dies wird in Ihrem Abschnitt zu engeren Limits behandelt, ist aber möglicherweise ausdrücklich erwähnenswert.
hash[foo"]"]=
, ${var-foo"}"}
, [[ "!" = b ]]
, [[ a = "]]" ]]
, die regexp Operatoren [[ x =~ ".+[" ]]
. Andere Keywords als {
( if
, while
, for
...) müssten zitiert werden , so sind sie nicht als solche erkannt ...
]
), daher liste ich sie nicht auf. Ich glaube nicht, dass ein Schlüsselwort in der Argumentposition zitiert werden muss.
In GNU Parallel wird dies ausgiebig getestet und verwendet:
$a =~ s/[\002-\011\013-\032\\\#\?\`\(\)\{\}\[\]\^\*\<\=\>\~\|\; \"\!\$\&\'\202-\377]/\\$&/go;
# quote newline as '\n'
$a =~ s/[\n]/'\n'/go;
Es wird geprüft , in bash
, dash
, ash
, ksh
, zsh
, und fish
. Einige der Charaktere müssen in einigen (Versionen) der Shells nicht zitiert werden, aber das Obige funktioniert in allen getesteten Shells.
Wenn Sie einfach eine Zeichenfolge in Anführungszeichen setzen möchten, können Sie sie wie folgt weiterleiten parallel --shellquote
:
printf "&*\t*!" | parallel --shellquote
Bei der einfachen Escape-Lösung in Perl verfolge ich das Prinzip der einfachen Anführungszeichen. Ein Bash-String in einfachen Anführungszeichen kann ein beliebiges Zeichen haben, mit Ausnahme des einfachen Anführungszeichens.
Mein Code:
my $bash_reserved_characters_re = qr([ !"#$&'()*;<>?\[\\`{|~\t\n]);
while(<>) {
if (/$bash_reserved_characters_re/) {
my $quoted = s/'/'"'"'/gr;
print "'$quoted'";
} else {
print $_;
}
}
Beispiellauf 1:
$ echo -n "abc" | perl escape_bash_special_chars.pl
abc
Beispiellauf 2:
echo "abc" | perl escape_bash_special_chars.pl
'abc
'
Beispiellauf 3:
echo -n 'ab^c' | perl escape_bash_special_chars.pl
ab^c
Beispiellauf 4:
echo -n 'ab~c' | perl escape_bash_special_chars.pl
'ab~c'
Beispiellauf 5:
echo -n "ab'c" | perl escape_bash_special_chars.pl
'ab'"'"'c'
echo 'ab'"'"'c'
ab'c