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 -flubset -o noglob .=Znak równości (U + 003D) również musi być uciekł jeśli set -kczyset -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#bjest w porządku, ale a #bjest 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 A0to 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