Widziałem kilka podobnych tematów, ale dotyczą one nie cytowania zmiennych, które, jak wiem, mogą prowadzić do niepożądanych wyników.
Widziałem ten kod i zastanawiałem się, czy byłoby możliwe wstrzyknięcie czegoś do uruchomienia po wykonaniu tej linii kodu:
echo run after_bundle
Odpowiedzi:
W konkretnym przypadku
cytowanie nie jest potrzebne. Nie jest potrzebne cytowanie, ponieważ argumentem
echo
są ciągi statyczne, które nie zawierają żadnych rozszerzeń zmiennych ani podstawień poleceń itp. Są to „tylko dwa słowa” (i jak podkreśla Stéphane , są one dodatkowo zbudowane z przenośnego zestawu znaków ).„Niebezpieczeństwo” pojawia się, gdy mamy do czynienia ze zmiennymi danymi, które powłoka może rozszerzać lub interpretować. W takich przypadkach należy uważać, aby powłoka działała prawidłowo i aby wynik był zgodny z przeznaczeniem.
Poniższe dwa pytania zawierają odpowiednie informacje na ten temat:
echo
jest czasem używany do „ochrony” potencjalnie szkodliwych poleceń w odpowiedziach na tej stronie. Na przykład mogę pokazać, jak usunąć pliki lub przenieść pliki do nowego miejsca docelowego za pomocąlub
Spowoduje to wyprowadzenie poleceń na terminal zamiast faktycznego usuwania lub zmiany nazw plików. Użytkownik może następnie sprawdzić polecenia, zdecydować, że wyglądają dobrze, usunąć
echo
i uruchomić ponownie.Twoje polecenie
echo run after_bundle
może być instrukcją dla użytkownika lub może być „zakomentowanym” fragmentem kodu, który jest zbyt niebezpieczny, aby działał bez znajomości konsekwencji.Używając w
echo
ten sposób, musisz wiedzieć, co robi zmodyfikowane polecenie i musisz zagwarantować, że zmodyfikowane polecenie jest w rzeczywistości bezpieczne (potencjalnie nie byłoby, gdyby zawierało przekierowania, a używanie go w potoku nie działa itp.)źródło
echo rm "first file.txt" "second file.txt"
w jakikolwiek sposób różni sięecho rm "first" "file.txt" "second" "file.txt"
, wynik obu jest taki sam. Jeśli chcesz wygenerować polecenie powłoki jako dane wyjściowe, musisz użyćprintf '%q ' rm "first file.txt" "second file.txt"; echo
lub czegoś równoważnego, który ponownie wygeneruje cytowanie składniowe, które zostanie ocenione jakoargv
przekazane.sh
potoku nie jest czymś niezwykłym, i widząc, że ludzie pytają „dlaczegofoo
działa, kiedy uruchamiam go w wierszu poleceń, ale ten skrypt, który emituje ten ciąg znakówecho
przed wierszem, nie działa? „ zdarza się tutaj cały czas . Co więcej, wynik debugowania nie jest pomocny, jeśli ukrywa twoje błędy - a jeśli twoje błędy są związane z cytowaniem, toecho
ich nie ujawni.Tylko dodatkowa uwaga na podstawie dobrej odpowiedzi @ Kusalananda .
jest w porządku, ponieważ żaden z tych 3 argumentów¹ nie przekazał
echo
znaków specjalnych dla powłoki.I (dodatkowy punkt, o którym chcę tu wspomnieć) nie ma ustawień regionalnych systemu, w których bajty te mogłyby zostać przetłumaczone na znaki specjalne dla powłoki.
Wszystkie te znaki są w tym, co POSIX nazywa przenośnym zestawem znaków . Znaki te powinny być obecne i zakodowane tak samo we wszystkich zestawach znaków w systemie POSIX².
Tak więc wiersz poleceń będzie interpretowany tak samo niezależnie od ustawień regionalnych.
Teraz, jeśli zaczniemy używać znaków spoza tego przenośnego zestawu znaków, dobrze jest zacytować je, nawet jeśli nie są one specjalne dla powłoki, ponieważ w innym ustawieniu narodowym bajty, które je tworzą, mogą być interpretowane jako różne znaki, które mogłyby specjalne dla powłoki. Zauważ, że chodzi o to, czy używasz
echo
czy jakiejkolwiek innej komendy, problem nie dotyczy,echo
ale sposobu, w jaki powłoka analizuje swój kod.Na przykład w UTF-8:
To
à
jest zakodowane jako 0xc3 0xa0. Teraz, jeśli masz ten wiersz kodu w skrypcie powłoki, a skrypt powłoki jest wywoływany przez użytkownika, który używa ustawień regionalnych, których zestaw znaków nie jest UTF-8, te dwa bajty mogą tworzyć bardzo różne znaki.Na przykład w
fr_FR.ISO8859-15
ustawieniach narodowych typowe ustawienia francuskie używające standardowego jednobajtowego zestawu znaków, który obejmuje język francuski (taki sam, jaki stosuje się w większości języków Europy Zachodniej, w tym angielskiego), bajt 0xc3 jest interpretowany jakoÃ
znak, a 0xa0 jako inny niż łamanie spacji.W niektórych systemach, takich jak NetBSD³, to nieprzerwane miejsce jest traktowane jako pusty znak (
isblank()
po zwróceniu wartości true, jest dopasowywany[[:blank:]]
) i powłoki w tenbash
sposób traktują go jako ogranicznik tokenów w swojej składni.Oznacza to, że zamiast uruchamiać
echo
z$'voil\xc3\xa0'
argumentem, uruchamiają go z$'voil\xc3'
argumentem, co oznacza, że nie zostanie wydrukowanyvoilà
poprawnie.To staje się dużo gorzej z chińskich zestawów znaków, takich jak BIG5, BIG5-HKSCS, GB18030, GBK, które mają wiele postaci, których kodowanie zawiera tego samego kodowania jak
|
,`
,\
(aby wymienić najgorszy) (również ten śmieszny SJIS, aka Microsoft Kanji, z wyjątkiem że jest¥
zamiast\
, ale nadal jest traktowany jak\
większość narzędzi, ponieważ jest tam zakodowany jako 0x5c).Na przykład, jeśli w
zh_CN.gb18030
chińskim języku, piszesz skrypt taki jak:Skrypt ten wyświetli się
詜 reboot
w lokalizacji używającej GB18030 lub GBK,唰 reboot
w lokalizacji używającej BIG5 lub BIG5-HKSCS, ale w lokalizacji C używającej ASCII lub lokalizacji używającej ISO8859-15 lub UTF-8, spowodujereboot
uruchomienie, ponieważ kodowanie GB18030 of詜
to 0xd4 0x7c, a 0x7c to kodowanie|
w ASCII, więc kończymy:(ten reprezentujący jednak bajt 0xd4 jest renderowany w ustawieniach regionalnych). Przykład użycia mniej szkodliwego
uname
zamiastreboot
:(
uname
był prowadzony).Tak więc radzę zacytować wszystkie ciągi zawierające znaki spoza przenośnego zestawu znaków.
Należy jednak pamiętać, że ponieważ kodowanie
\
i`
znajdują się w kodowaniu niektórych z tych znaków, lepiej nie używać\
lub"..."
lub$'...'
(wewnątrz których`
i / lub\
nadal są specjalne), a'...'
zamiast tego cytować znaki spoza przenośnego zestawu znaków.Nie znam żadnego systemu, który ma ustawienia narodowe, w których zestaw znaków ma dowolny znak (
'
oczywiście inny niż sam), którego kodowanie zawiera kodowanie'
, więc te'...'
powinny być zdecydowanie najbezpieczniejsze.Zauważ, że kilka powłok obsługuje również
$'\uXXXX'
zapis do wyrażania znaków na podstawie ich punktu kodowego Unicode. W powłokach takich jakzsh
ibash
znak jest wstawiany zakodowany w zestawie znaków regionu (chociaż może powodować nieoczekiwane zachowania, jeśli ten zestaw znaków nie ma tego znaku). Pozwala to uniknąć wstawiania znaków innych niż ASCII do kodu powłoki.Tak więc powyżej:
Lub:
(z zastrzeżeniem może on uszkodzić skrypt, gdy zostanie uruchomiony w lokalizacjach, które nie mają tych znaków).
Lub lepiej, ponieważ
\
jest również specjalny dlaecho
(lub przynajmniej niektórychecho
implementacji, przynajmniej tych zgodnych z Uniksem):(zauważ, że
\
jest to również specjalne w pierwszym argumencie doprintf
, więc lepiej jest unikać znaków spoza ASCII, na wypadek, gdyby mogły zawierać kodowanie\
).Pamiętaj, że możesz także:
(byłoby to przesadą, ale mogłoby ci dać spokój, jeśli nie jesteś pewien, które postacie znajdują się w przenośnym zestawie znaków)
Upewnij się także, aby nigdy nie używać starożytnej
`...`
formy zastępowania poleceń (która wprowadza kolejny poziom przetwarzania odwrotnego ukośnika), ale używaj$(...)
zamiast tego.¹ technicznie,
echo
jest również przekazywana jako argument doecho
narzędzia (aby poinformować go, jak został wywołany), to jest toargv[0]
iargc
to 3, chociaż w większości powłok obecnieecho
jest wbudowane, tak żeexec()
z/bin/echo
pliku z listy 3 argumentów jest symulowane przez muszla. Często uważa się, że lista argumentów zaczyna się od drugiej (argv[1]
doargv[argc - 1]
), ponieważ to na nią głównie działają polecenia.² znaczący wyjątek od tej niedorzecznej
ja_JP.SJIS
lokalizacji systemów FreeBSD, których zestaw znaków nie ma\
ani~
charakteru!³ zauważ, że podczas gdy wiele systemów (FreeBSD, Solaris, a nie GNU) uważa U + 00A0 za lokalizację
[[:blank:]]
w ustawieniach UTF-8, nieliczne robią to w innych ustawieniach, takich jak ISO8859-15, być może w celu uniknięcia tego rodzaju problemów.źródło
echo
...”, liczę tylko 2 argumenty przekazane do poleceniaecho
, argumenty, które mogę policzyć,run
iafter_bundle
, staram się wyjaśnić, jak policzyłem i dostałem 3 argumenty?echo
). Zobacz(exec -a foo /bin/echo --help)
w systemie GNU i powłoce GNU, jak przekazać arbitralny pierwszy argument do/bin/echo
narzędzia.$0
i parametry pozycyjne w powłokach.iconv
w którychESC
jest konwertowany na'
. Spróbuj (jako przykład):printf '\x1b'|iconv -f utf8 -t IBM-937|xxd
'
. Spróbowaćprintf '\u2804' | iconv -f utf8 -t BRF | xxd
. Istnieją kodowania, w których powstaje wiele współrzędnych kodowych'
. Staje się około 8695 współrzędnych kodowych w UCS-4'
. Spróbowaćprintf '\U627' | iconv -cf utf-8 -t UCS-4
. Kilka (37) kodowań przekształca znak 0x127 na a'
. Spróbujprintf '\U127' | iconv -cf utf8 -t UCS2 |xxd