W języku Bash, kiedy należy podać argumenty wiersza polecenia, jakie znaki należy uciec?
Są one ograniczone do metaznakami bash: przestrzeni, karcie
|
, &
, ;
, (
, )
, <
, i >
?
W języku Bash, kiedy należy podać argumenty wiersza polecenia, jakie znaki należy uciec?
Są one ograniczone do metaznakami bash: przestrzeni, karcie
|
, &
, ;
, (
, )
, <
, i >
?
Odpowiedzi:
Następujące znaki mają specjalne znaczenie dla samej powłoki w niektórych kontekstach i może wymagać zmiany znaczenia w argumentach:
`
Backtick (U + 0060 Grave Accent)~
Tylda (U + 007E)!
Wykrzyknik (U + 0021)#
Hash (znak numeryczny U + 0023)$
Znak dolara (U + 0024)&
Ampersand (U + 0026)*
Gwiazdka (U + 002A)(
Lewy nawias (U + 0028))
Prawy nawias (U + 0029)
( ⇥
) Zakładka (U + 0009){
Lewy nawias klamrowy (U + 007B Lewy nawias klamrowy )[
Lewy nawias kwadratowy (U + 005B)|
Pionowy pasek (linia pionowa U + 007C)\
Odwrotny ukośnik (U + 005C do tyłu Solidus);
Średnik (U + 003B)'
Pojedynczy cytat / apostrof (U + 0027)"
Podwójny cytat (U + 0022)↩
Nowa linia (U + 000A)<
Mniej niż (U + 003C)>
Większy niż (U + 003E)?
Znak zapytania (U + 003F)
Spacja (U + 0020) 1Niektóre z tych znaków są używane do więcej rzeczy i w większej liczbie miejsc niż ta, którą połączyłem.
Istnieje kilka przypadków narożnych, które są wyraźnie opcjonalne:
!
można wyłączyć za pomocą set +H
, co jest domyślne w nieinteraktywnych powłokach.{
można wyłączyć za pomocą set +B
.*
i ?
można je wyłączyć za pomocą set -f
lubset -o noglob
.=
Znak równości (U + 003D) również musi być uciekł jeśli set -k
czyset -o keyword
jest włączona.Ucieczka od nowego wiersza wymaga cytowania - odwrotne ukośniki nie wykonają zadania. Wszelkie inne znaki wymienione w IFS będą wymagały podobnej obsługi. Nie trzeba uciekać ]
albo }
, ale nie trzeba uciekać )
, bo to operator.
Niektóre z tych postaci mają ścisłe ograniczenia, kiedy naprawdę potrzebują ucieczki, niż inne. Na przykład a#b
jest w porządku, ale a #b
jest komentarzem, podczas gdy >
musiałby uciekać w obu kontekstach. Zresztą nie zaszkodzi im uciec zachowawczo i jest to łatwiejsze niż zapamiętanie drobnych różnic.
Jeśli sama nazwa polecenia jest kluczowe shell ( if
, for
, do
), a następnie będziesz musiał uciec lub zacytować go zbyt. Jedyny interesujący z nich to in
, ponieważ nie jest oczywiste, że zawsze jest to słowo kluczowe. Ci nie muszą tego robić dla słów kluczowych używanych w argumentach, tylko wtedy, gdy masz (głupio!) O nazwie polecenia po jednym z nich. Operatorzy powłoki ( (
, &
itp.) Zawsze potrzebują cytowania, gdziekolwiek się znajdują.
1 Stéphane zauważył, że każda inna jednobajtowa pusta postać z twojego regionu również potrzebuje ucieczki. W najczęstszych, rozsądnych lokalizacjach, przynajmniej tych opartych na C lub UTF-8, są to tylko powyższe białe znaki. W niektórych lokalizacjach ISO-8859-1 przestrzeń bez przerw U + 00A0 jest uważana za pustą, w tym Solaris, BSD i OS X (myślę niepoprawnie). Jeśli masz do czynienia z dowolnym nieznanym miejscem, może ono zawierać prawie wszystko, w tym litery, więc powodzenia.
Można sobie wyobrazić, że pojedynczy bajt uważany za pusty może pojawiać się w wielobajtowym znaku, który nie był pusty, i nie byłoby sposobu, aby uciec od tego, poza umieszczeniem całego zdania w cudzysłowie. Nie jest A0
to kwestia teoretyczna: w ustawieniu ISO-8859-1 z góry ten bajt, który jest uważany za pusty, może pojawiać się w znakach wielobajtowych, takich jak UTF-8 zakodowane „à” ( C3 A0
). Aby bezpiecznie obchodzić się z tymi postaciami, musisz je zacytować "à"
. To zachowanie zależy od konfiguracji ustawień regionalnych w środowisku, w którym działa skrypt, a nie od tego, w którym został napisany.
Myślę, że to zachowanie jest zepsute na wiele sposobów, ale musimy rozgrywać rozdanie, które otrzymaliśmy. Jeśli pracujesz z dowolnym niesynchronizującym wielobajtowym zestawem znaków, najbezpieczniej byłoby zacytować wszystko. Jeśli jesteś w UTF-8 lub C, jesteś bezpieczny (na razie).
!
gdy włączone jest rozszerzanie historii csh, zwykle nie w skryptach. [ ! -f a ]
lub find . ! -name...
są w porządku. Jest to omówione w części dotyczącej bardziej rygorystycznych limitów, ale może warto o tym wyraźnie wspomnieć.
hash[foo"]"]=
, ${var-foo"}"}
, [[ "!" = b ]]
, [[ a = "]]" ]]
, operatorzy regexp dla [[ x =~ ".+[" ]]
. Inne niż słowa kluczowe {
( if
, while
, for
...) musiałby być cytowane więc nie są one rozpoznawane jako takie ...
]
), więc nie wymienię ich. Nie sądzę, aby jakieś słowo kluczowe wymagało cytowania w pozycji argumentu.
W GNU Parallel jest to testowane i szeroko stosowane:
$a =~ s/[\002-\011\013-\032\\\#\?\`\(\)\{\}\[\]\^\*\<\=\>\~\|\; \"\!\$\&\'\202-\377]/\\$&/go;
# quote newline as '\n'
$a =~ s/[\n]/'\n'/go;
Jest on testowany w bash
, dash
, ash
, ksh
, zsh
, i fish
. Niektóre znaki nie wymagają cytowania w niektórych (wersjach) powłok, ale powyższe działa we wszystkich testowanych powłokach.
Jeśli chcesz po prostu zacytować ciąg, możesz go potokować w parallel --shellquote
:
printf "&*\t*!" | parallel --shellquote
W przypadku lekkiego rozwiązania ucieczki w Perlu, kieruję się zasadą pojedynczych cudzysłowów. Ciąg Bash w pojedynczych cudzysłowach może mieć dowolny znak, z wyjątkiem samego pojedynczego cudzysłowu.
Mój kod:
my $bash_reserved_characters_re = qr([ !"#$&'()*;<>?\[\\`{|~\t\n]);
while(<>) {
if (/$bash_reserved_characters_re/) {
my $quoted = s/'/'"'"'/gr;
print "'$quoted'";
} else {
print $_;
}
}
Przykładowy przebieg 1:
$ echo -n "abc" | perl escape_bash_special_chars.pl
abc
Przykładowy przebieg 2:
echo "abc" | perl escape_bash_special_chars.pl
'abc
'
Przykładowy przebieg 3:
echo -n 'ab^c' | perl escape_bash_special_chars.pl
ab^c
Przykładowy przebieg 4:
echo -n 'ab~c' | perl escape_bash_special_chars.pl
'ab~c'
Przykładowy przebieg 5:
echo -n "ab'c" | perl escape_bash_special_chars.pl
'ab'"'"'c'
echo 'ab'"'"'c'
ab'c