Dlaczego rozszerzenie zmiennej bash zachowuje cytaty?

12
> echo "hi"
hi
> VAR='echo "hi"'
> $VAR
"hi"

Dlaczego wyjście powyższych poleceń jest inne?

Podobnie dzieje się z pojedynczymi cudzysłowami:

> VAR="echo 'hi'"
> $VAR
> 'hi'
Cory Klein
źródło
6
Proszę nie przyzwyczajać się do osadzania wykonywalnych fragmentów skryptu w zmiennych. W najlepszym wypadku evaljest to
obchodzić
@ jw013 Dobra uwaga i świetne artykuły. Podoba mi się cytat „Zmienne przechowują dane, funkcje przechowują kod”. z pierwszego linku, ale na mój użytek, dane podane funkcji (w tym przypadku at) to kod. Czy masz jakieś wskazówki na temat bezpieczniejszego sposobu organizowania / zbierania kodu at?
Cory Klein
atprzyjmuje shskładnię jako dane wejściowe. W ten sposób generowanie danych wejściowych atoznacza generowanie poprawnej, poprawnie cytowanej shskładni z dowolnych danych wejściowych, co nie jest trywialne, więc starałbym się tego unikać, jeśli to w ogóle możliwe. Byłoby naprawdę pomocne, gdybyś mógł podać trochę więcej szczegółów na temat tego, co próbujesz osiągnąć.
jw013
Przepraszam, nie chciałem rozpraszać się zbyt dużą ilością szczegółów, ale to, co robię, nie jest tak naprawdę skomplikowane, IMO. Tworzę skrypt, który wymaga „czasu” i „wiadomości”. Następnie działa atprzez określony „czas” i każe aturuchomić polecenie dzen2. dzen2pobiera „wiadomość” ze standardowego wejścia, a także wykorzystuje inne parametry statyczne. Trudność polega na tym, że muszę przesłać parametr „message” od użytkownika do dzen2polecenia, ale tak naprawdę nie uruchamiam dzen2się, mówię atto zrobić.
Cory Klein
1
superuser.com/questions/360966/… || stackoverflow.com/questions/7454526/...
Ciro Santilli 新疆 改造 中心 法轮功 六四 事件

Odpowiedzi:

16

Dodatkowa para cytatów zostanie wykorzystana tylko w dodatkowym etapie oceny. Na przykład wymuszony przez eval:

bash-4.2$ VAR='echo "hi"'

bash-4.2$ $VAR
"hi"

bash-4.2$ eval $VAR
hi

Ale ogólnie rzecz biorąc, złym pomysłem jest umieszczanie poleceń z parametrami w jednym ciągu. Zamiast tego użyj tablicy:

bash-4.2$ VAR=(echo "hi")

bash-4.2$ "${VAR[@]}"
hi
człowiek w pracy
źródło
1
Należy również zauważyć, że cytaty są oceniane inaczej; podwójne cudzysłowy („) pozwalają na ocenę załączonego ciągu, pojedyncze cudzysłowy (') drukują ciąg jako literał. Przykład: "$(ls)"i '$(ls)'. To jest powód, dla którego cytaty pojawiają się w przykładach oryginalnych pytań.
Joseph Kern
Tablica jest również źródłem problemów. Kod należy do funkcji, dane do zmiennych. Prezentowany przykład działa tylko dlatego, że cudzysłowy są usuwane w podziale tablicy. A printf '<%s> ' "${VAR[@]}"pokaże, że cytaty zostały już usunięte. Jeśli ustawisz VAR tak, VAR=(echo \"hi\")aby faktycznie zawierał cytaty, ten sam problem pojawi się ponownie, $ ${VAR[@]}wydrukuje"hi"
9

Usuwanie cytatów następuje tylko w przypadku oryginalnych słów wejściowych, a nie w wyniku rozwinięć. Cytaty będące częścią zmiennych rozszerzonych pozostają nietknięte.

jw013
źródło
2

Jeśli cofniesz się nieco, zobaczysz, dlaczego podstawienie zmiennej absolutnie powinno zachować cudzysłowy.

Celem cudzysłowów w powłoce Unix / Linux / BSD jest trzymanie razem kawałków łańcucha, które inaczej zostałyby przeanalizowane jako wiele łańcuchów. Ponieważ domyślnie powłoka używa białych znaków jako separatora tokenów, ciąg znaków ze spacjami (np. „Jeden dwa trzy”), jeśli nie zostanie cytowany lub nie zostanie w żaden sposób poprzedzony znakiem ucieczki, zostanie sparsowany jako 3 łańcuchy: „jeden”, „dwa” i „trzy”.

Jeśli programista chce łańcucha z wartością interpolowanej zmiennej:

VAR=two
STRING="one $VAR three"

powłoka absolutnie nie powinna usuwać cudzysłowów: ciąg zawierający spacje zostałby przeanalizowany jako 3 mniejsze ciągi.

Bruce Ediger
źródło