Powłoka POSIX: czy `$` traci swoje specjalne znaczenie, jeśli jest ostatnim znakiem w słowie?

17

Na popiołu, biegu i uderzeniu, kiedy biegnę

$ echo ab$

powraca

ab$

Czy takie zachowanie jest określone przez POSIX, czy jest to tylko powszechna konwencja w powłokach zgodnych z POSIX? Nie mogłem znaleźć niczego na stronie języka poleceń powłoki POSIX, która wspomniałaby o tym zachowaniu.

Harold Fischer
źródło
4
Lepszym pytaniem jest: „Czy $ nabiera specjalnego znaczenia, jeśli jest to ostatni znak w słowie?” Nie przypisano żadnego specjalnego znaczenia $; służy do wprowadzania wielu, ale odrębnych rozszerzeń, takich jak interpretacja parametrów ${...}, podstawianie poleceń $(...)i wyrażenia arytmetyczne $((...)). Niektóre powłoki wprowadzają dodatkowe konteksty, takie jak kshwariant zastępowania poleceń x=${ echo foo; echo bar;}(który różni się od standardu, $(...)ponieważ nie wykonuje poleceń w podpowłoce).
chepner
@chepner Czy chciałbyś zastanowić się nad różnicą zdań między Issac a Michaelem Homerem? Ich odpowiedzi są wprost sprzeczne
Harold Fischer
1
Zgadzam się z interpretacją Michaela Homera; powłoka nie zaczyna się nawet martwić rozszerzeniami, dopóki nie zakończy się parsowanie, więc w jednym słowie ab$nie ma znaku po nim $, bez względu na to, czy po nim następował znak null w oryginalnym ciągu wejściowym czy spacja w przypadku jak echo ab$ foo; oryginalna niecytowana biała spacja została rozpoznana i odrzucona po analizie.
chepner

Odpowiedzi:

10

$sam w sobie nie ma specjalnego znaczenia (try echo $), tylko w połączeniu z innym znakiem po nim i tworzącym rozwinięcie, np. $var(lub ${var}) $(util),, $((1+2)).

$Staje się jego „specjalny”, czyli jak definiowanie ekspansję w standardzie POSIX ramach sekcji Reklamowe Recognition :

Jeśli bieżący znak jest niecytowany $lub `, powłoka identyfikuje początek dowolnych kandydatów do interpretacji parametrów, podstawiania poleceń lub interpretacji arytmetycznej na podstawie ich wprowadzających, niecytowanych sekwencji znaków: $lub ${, $(lub `, i $((, odpowiednio. Powłoka powinna czytać wystarczającą ilość danych wejściowych, aby określić koniec jednostki, która ma zostać rozwinięta ( jak wyjaśniono w cytowanych sekcjach). Podczas przetwarzania znaków, jeśli wystąpią rozszerzenia lub cytowanie zagnieżdżone w podstawieniu, powłoka będzie rekurencyjnie przetwarzać je w sposób określony dla znalezionej konstrukcji. Znaki znalezione od początku podstawienia do jego końca, pozwalające na rekurencję konieczną do rozpoznania wbudowanych konstrukcji, zostaną uwzględnione w niezmodyfikowanej postaci w tokenie wyniku, w tym wszelkie osadzone lub zawierające operatory podstawienia lub cytaty. Token nie będzie ograniczany przed końcem zamiany.

Jeśli więc $nie tworzy rozwinięcia, obowiązują inne reguły analizy:

Jeżeli poprzedni znak był częścią słowa, bieżący znak należy dołączyć do tego słowa.

To obejmuje twój ab$sznurek.

W przypadku samotnego $(„nowym słowem” byłoby $samo w sobie):

Bieżący znak jest używany jako początek nowego słowa.

Znaczenie wytworzonego słowa zawierających $która nie jest średnia rozprężania wyraźnie zdefiniowane jako nieokreślone POSIX.

Zauważ też, że $jest to ostatni znak $$, ale zdarza się, że jest to zmienna, która przechowuje PID bieżącej powłoki. W bash, !$może wywołać rozszerzenie historii (ostatni argument poprzedniej komendy). Ogólnie rzecz biorąc, nie, $nie jest pozbawione znaczenia na końcu niecytowanego słowa, ale na końcu słowa przynajmniej nie oznacza standardowego rozwinięcia.

Kusalananda
źródło
7

W zależności od dokładnej sytuacji jest to albo jawnie nieokreślone (więc implementacje mogą robić, co chcą), albo wymagane, aby tak się stało. W swoim dokładnym scenariuszem echo ab$, POSIX nakazuje wyjście „ab $”, który obserwuje i nie jest nieokreślona . Szybkie podsumowanie wszystkich różnych przypadków znajduje się na końcu.

Istnieją dwa elementy: najpierw tokenizowanie na słowa, a następnie interpretacja tych słów.


Tokenizacja

Tokenizacja POSIX wymaga, aby a, $który nie jest początkiem prawidłowego rozszerzenia parametru , podstawienia polecenia lub podstawienia arytmetycznego, był uważany za dosłowną część WORDbudowanego tokena. Wynika to z reguły 5 („Jeśli bieżący znak jest niecytowany $lub `, powłoka rozpoznaje początek dowolnych kandydatów do interpretacji parametrów, podstawiania poleceń lub interpretacji arytmetycznej na podstawie ich wprowadzających, niecytowanych sekwencji znaków: $lub ${, $(lub `, i $((, odpowiednio” ) nie ma zastosowania, ponieważ żadne z tych rozszerzeń nie jest tam wykonalne. Rozwinięcie parametrów wymaga pojawienia się tam poprawnej nazwy, a pusta nazwa nie jest poprawna.

Ponieważ ta zasada nie miała zastosowania, kontynuujemy jej przestrzeganie, dopóki nie znajdziemy takiej, która ją spełnia. Dwaj kandydaci to # 8 („Jeśli poprzedni znak był częścią słowa, bieżący znak zostanie dołączony do tego słowa.”) I nr 10 („Bieżący znak jest używany jako początek nowego słowa.”) , które dotyczą odpowiednio echo a$i echo $.

Istnieje również trzeci przypadek formy, echo a$+bktóra przechodzi przez to samo pęknięcie, ponieważ +nie jest to nazwa specjalnego parametru. Do tego wrócimy później, ponieważ uruchamia różne części reguł.

Specyfikacja wymaga zatem, aby $była uważana za część słowa składniowo, a następnie może być dalej przetwarzana.


Rozwijanie wyrazów

Po przeanalizowaniu danych wejściowych w ten sposób, z $zawartym w nim słowem, do każdego z przeczytanych słów stosowane są rozwinięcia słów. Każde słowo jest przetwarzane indywidualnie .

Określono, że :

Jeśli po nie cytowanym znaku „$” występuje znak, który nie jest jednym z poniższych:

  • Znak numeryczny
  • Nazwa jednego z parametrów specjalnych (patrz Parametry specjalne )
  • Prawidłowy pierwszy znak nazwy zmiennej
  • A <left-curly-bracket>(„{”)
  • ZA <left-parenthesis>

wynik jest nieokreślony.

„Nieokreślony” jest tu szczególnym określeniem

  1. W tym przypadku zgodna powłoka może wybrać dowolne zachowanie
  2. Zgodna aplikacja nie może polegać na żadnym konkretnym zachowaniu

W przykładzie echo ab$, $ nie następuje dowolnym charakterze , więc zasada ta nie ma zastosowania, a nieokreślone wynik nie jest wywoływany. Po prostu nie ma na to żadnego rozszerzenia $, więc jest dosłownie obecny i wydrukowany.

Gdzie byłoby zastosować w naszym trzecim przypadku z góry: echo a$+b. Tutaj $następuje +, która nie jest liczbą, specjalny parametr ( @, *, #, ?, -, $, !, lub 0), zacznij od zmiennej nazwy (podkreślenia lub alfabetycznym z przenośnego zestawu znaków ), lub jeden z uchwytów. W tym przypadku zachowanie jest nieokreślony: a powłoka zgodna jest dozwolone wynaleźć specjalny parametr zwany +poszerzyć i zgodny wniosek nie należy zakładać, że powłoka nie . Powłoka mogłaby również robić wszystko, co lubiła, w tym zgłaszać błąd.

Na przykład, zsh, w tym w trybie POSIX, interpretuje $+bjako „ bzestaw zmiennych ” i zastępuje 1 lub 0 zamiast niego. Podobnie ma rozszerzenia dla ~i =. To jest zgodne zachowanie.

Innym miejscem, w którym może się to zdarzyć, jest echo "a$ b". Ponownie, powłoka może robić, co chce, a ty jako autor skryptu powinieneś uciec, $jeśli chcesz dosłowny wynik. Jeśli tego nie zrobisz, może działać, ale nie możesz na nim polegać. Jest to bezwzględna litera specyfikacji, ale nie sądzę, aby ten rodzaj szczegółowości był zamierzony lub rozważany.


W podsumowaniu

  • echo ab$: wyjście literału, w pełni określone
  • echo a$ b: wyjście literału, w pełni określone
  • echo a$ b$: wyjście literału, w pełni określone
  • echo a$b: rozszerzenie parametru b, w pełni określone
  • echo a$-b: rozszerzenie parametru specjalnego -, w pełni określone
  • echo a$+b: nieokreślone zachowanie
  • echo "a$ b": nieokreślone zachowanie

Na $końcu słowa możesz polegać na zachowaniu, które musi być traktowane dosłownie i przekazywane echopoleceniu jako część jego argumentu. Jest to wymóg zgodności z powłoką.

Michael Homer
źródło
Komentarze nie są przeznaczone do rozszerzonej dyskusji; ta rozmowa została przeniesiona do czatu .
terdon
@MichaelHomer Czy byłby echo $również dosłowny i w pełni określony?
Harold Fischer
@HaroldFischer Tak
Michael Homer
Gdzie echo "$" i gdzie echo "a b$"spaść?
Harold Fischer