Czy jest jakaś obszerna lista postaci, które należy uciec w Bash? Czy można to sprawdzić tylko za pomocą sed
?
W szczególności sprawdzałem, czy %
trzeba uciec, czy nie. próbowałem
echo "h%h" | sed 's/%/i/g'
i działało dobrze, bez ucieczki %
. Czy to znaczy, %
że nie trzeba uciekać? Czy to był dobry sposób na sprawdzenie konieczności?
I bardziej ogólnie: czy są to te same postacie, do których można uciec shell
i bash
?
Odpowiedzi:
Istnieją dwie proste i bezpieczne zasady, które działają nie tylko w,
sh
ale takżebash
.1. Umieść cały ciąg w pojedynczych cudzysłowach
Działa to dla wszystkich znaków, z wyjątkiem pojedynczego cudzysłowu. Aby uniknąć pojedynczego cytatu, zamknij cytat przed nim, wstaw pojedynczy cytat i ponownie otwórz cytat.
polecenie sed:
sed -e "s/'/'\\\\''/g; 1s/^/'/; \$s/\$/'/"
2. Unikaj każdego znaku odwrotnym ukośnikiem
Działa to dla wszystkich znaków z wyjątkiem znaku nowej linii. W przypadku znaków nowej linii użyj pojedynczych lub podwójnych cudzysłowów. Puste ciągi muszą być nadal obsługiwane - zamień na
""
sed polecenie:
sed -e 's/./\\&/g; 1{$s/^$/""/}; 1!s/^/"/; $!s/$/"/'
.2b. Bardziej czytelna wersja 2
Istnieje łatwy bezpieczny zestaw znaków, takich jak
[a-zA-Z0-9,._+:@%/-]
, które można pozostawić bez ukrycia, aby był bardziej czytelnysed polecenie:
LC_ALL=C sed -e 's/[^a-zA-Z0-9,._+@%/-]/\\&/g; 1{$s/^$/""/}; 1!s/^/"/; $!s/$/"/'
.Zauważ, że w programie sed nie wiadomo, czy ostatni wiersz danych wejściowych kończy się bajtem nowej linii (chyba że jest pusty). Dlatego oba powyższe polecenia sed zakładają, że tak nie jest. Możesz dodać cytowany znak nowej linii ręcznie.
Zauważ, że zmienne powłoki są zdefiniowane tylko dla tekstu w sensie POSIX. Przetwarzanie danych binarnych nie jest zdefiniowane. W przypadku implementacji, które mają znaczenie, plik binarny działa z wyjątkiem bajtów NUL (ponieważ zmienne są implementowane za pomocą ciągów C i przeznaczone do użycia jako ciągi C, a mianowicie argumenty programu), ale należy przełączyć się na ustawienia „binarne”, takie jak latin1 .
(Możesz łatwo zweryfikować reguły, czytając specyfikację POSIX dla
sh
. W przypadku bash sprawdź podręcznik referencyjny połączony przez @AustinPhillips)źródło
sed
, ale wymagabash
.format, który można ponownie wykorzystać jako dane wejściowe powłoki
Dla tego rodzaju żądań stworzono specjalną
printf
dyrektywę formatu (%q
):Niektóre próbki:
Można to również wykorzystać poprzez zmienne:
Szybkie sprawdzenie wszystkich (128) bajtów ascii:
Zauważ, że wszystkie bajty od 128 do 255 muszą być poprzedzone znakami ucieczki.
To musi renderować coś takiego:
Tam, gdzie pierwsze pole jest wartością szesnastkową bajtu, drugie zawiera,
E
jeśli znak musi być poprzedzony znakiem ucieczki, a trzecie pole pokazuje znak zmiany znaczenia.Dlaczego
,
?Można zobaczyć kilka znaków, które nie zawsze muszą być uciekł, jak
,
,}
i{
.Więc nie zawsze, ale kiedyś :
lub
ale dbaj:
źródło
subprocess.Popen(['bash', '-c', 'printf "%q\0" "$@"', '_', arbitrary_string], stdin=subprocess.PIPE, stdout=subprocess.PIPE).communicate()
otrzymasz poprawnie cytowaną wersję powłokiarbitrary_string
.%q
był zepsuty przez długi czas - Jeśli mój umysł dobrze mi służy, błąd został naprawiony (ale nadal może być zepsuty) w 2013 roku po tym, jak został zepsuty przez ~ 10 lat. Więc nie polegaj na tym.shlex.quote()
(> = 3.3,pipes.quote()
- nieudokumentowane - dla starszych wersji) również wykona zadanie i stworzy wersję bardziej czytelną dla ludzi (w razie potrzeby dodając cudzysłowy i znaki specjalne), bez potrzeby odradzania powłoki.,
. Byłem zaskoczony, gdy dowiedziałem się, że wbudowany Bashprintf -- %q ','
daje\,
, ale/usr/bin/printf -- %q ','
daje,
(bez ucieczki). Takie same dla innych znaków:{
,|
,}
,~
.Aby uratować kogoś innego przed koniecznością korzystania z RTFM ... w bash :
... więc jeśli je unikniesz (i oczywiście sam cytat), prawdopodobnie nic ci nie jest.
Jeśli zastosujesz bardziej konserwatywne podejście „w razie wątpliwości, unikaj go”, powinno być możliwe uniknięcie uzyskiwania znaków o specjalnym znaczeniu, nie unikając znaków identyfikacyjnych (tj. Liter ASCII, cyfr lub „_”). Jest bardzo mało prawdopodobne, aby kiedykolwiek (tj. W jakiejś dziwnej powłoce POSIX-owej) miał specjalne znaczenie i dlatego trzeba go uciec.
źródło
Korzystając z tej
print '%q'
techniki , możemy uruchomić pętlę, aby dowiedzieć się, które znaki są wyjątkowe:Daje to wynik:
Niektóre wyniki, na przykład
,
wyglądają trochę podejrzanie. Byłoby interesujące uzyskać wkład @ CharlesDuffy na ten temat.źródło
,
wyglądać trochę podejrzanie w ostatnim akapicie mojej odpowiedzi%q
nie wie, gdzie w powłoce planujesz użyć znaku, więc ucieknie on od wszystkich znaków, które mogą mieć specjalne znaczenie w każdym możliwym kontekście powłoki.,
samo w sobie nie ma specjalnego znaczenia dla jej powłoki, ale jak zauważył @ F.Hauri w swojej odpowiedzi, ma specjalne znaczenie w{...}
rozszerzaniu nawiasów klamrowych: gnu.org/savannah-checkouts/gnu/bash/manual/… To jest jak! co również wymaga rozszerzenia w określonych sytuacjach, a nie ogólnie:echo Hello World!
działa dobrze, aleecho test!test
zawiedzie.Znaki wymagające ucieczki są inne w powłoce Bourne'a lub POSIX niż Bash. Ogólnie (bardzo) Bash jest nadzbiorem tych pocisków, więc wszystko, w czym uciekasz,
shell
powinno być ucieczką w Bash.Dobrą ogólną zasadą byłoby „jeśli masz wątpliwości, unikaj tego”. Ale ucieczka przed niektórymi postaciami nadaje im specjalne znaczenie
\n
. Są one wymienione naman bash
stronach podQuoting
iecho
.Poza tym, unikaj znaków, które nie są alfanumeryczne, jest to bezpieczniejsze. Nie znam jednej ostatecznej listy.
Strony podręcznika wymieniają je wszystkie gdzieś, ale nie w jednym miejscu. Naucz się języka, to jest sposób, aby być pewnym.
Tym, który mnie złapał, jest
!
. Jest to znak specjalny (rozszerzenie historii) w Bash (i csh), ale nie w powłoce Korna.echo "Hello world!"
Daje nawet problemy. Używanie pojedynczych cudzysłowów, jak zwykle, usuwa specjalne znaczenie.źródło
sed
wystarczającej ilości informacji pozwala sprawdzić, czy należy uciec. Dziękuję za odpowiedź!sed
nie jest konieczne, możesz sprawdzić za pomocą prawie wszystkiego.sed
nie jest problemem,bash
jest. Wewnątrz pojedynczych cudzysłowów nie ma znaków specjalnych (oprócz pojedynczych cudzysłowów), nie można nawet uciec przed nimi.sed
Polecenie powinno być zwykle wewnątrz pojedynczych cudzysłowów bo metaznakami RE mają zbyt wiele interferencji z metaznaki powłoki pewności. Wyjątkiem jest osadzanie zmiennych powłoki, co należy zrobić ostrożnie.echo
. Jeśli wydostaniesz się z tego, co wkładasz, nie musisz uciekać. :)Zakładam, że mówisz o ciągach bash. Istnieją różne typy ciągów, które mają inny zestaw wymagań dotyczących ucieczki. na przykład. Ciągi pojedynczych cudzysłowów różnią się od ciągów podwójnych cudzysłowów.
Najlepszym źródłem informacji jest sekcja Cytowanie w podręczniku bash.
Wyjaśnia, które postacie potrzebują ucieczki. Pamiętaj, że niektóre znaki mogą wymagać ucieczki w zależności od włączonych opcji, takich jak rozszerzanie historii.
źródło
Zauważyłem, że bash automatycznie ucieka niektórym postaciom podczas korzystania z autouzupełniania.
Na przykład, jeśli masz katalog o nazwie
dir:A
, bash automatycznie się uzupełnidir\:A
Korzystając z tego, przeprowadziłem kilka eksperymentów z wykorzystaniem znaków z tabeli ASCII i wyprowadziłem następujące listy:
Znaki, które bash ucieka przy autouzupełnianiu : (zawiera spację)
Znaki, które bash nie ucieka :
(Wykluczyłem
/
, ponieważ nie można go używać w nazwach katalogów)źródło
printf %q
zmieniają się i nie modyfikują, jeśli zostaną przekazane jako argument - najlepiej przejrzyj cały zestaw znaków.