W tym pytaniu ktoś zgłasza problem z użyciem dokumentu tutaj z cytowanym słowem ogranicznika w $(...)
podstawianiu poleceń , gdzie odwrotny ukośnik \
na końcu linii w dokumencie powoduje kontynuację linii łączącej nową linię , podczas gdy ten sam dokument tutaj podstawienie polecenia poza operacją działa zgodnie z oczekiwaniami .
Oto uproszczony przykładowy dokument:
cat <<'EOT'
abc ` def
ghi \
jkl
EOT
Obejmuje to jeden lewy i jeden lewy ukośnik na końcu linii. Separator jest cytowany, więc wewnątrz ciała nie występują żadne rozszerzenia. We wszystkich Bourne-alike'ach mogę znaleźć te dane wyjściowe dosłownie. Jeśli wstawię ten sam dokument do podstawienia polecenia w następujący sposób:
x=$(cat <<'EOT'
abc ` def
ghi \
jkl
EOT
)
echo "$x"
wtedy nie zachowują się już identycznie:
dash
,ash
,zsh
,ksh93
, BusyBoxash
,mksh
i SunOS 5.10 POSIXsh
wszystkim dać Verbatim zawartość dokumentu, jak poprzednio.- Bash 3.2 podaje błąd składniowy dla niedopasowanego backsticka. Przy dopasowanych backticksach próbuje uruchomić zawartość jako polecenie.
- Bash 4.3 zwija „ghi” i „jkl” w jednym wierszu, ale nie ma błędu.
--posix
Opcja nie ma wpływu na to. Kusalananda mówi mi (dzięki!), Żepdksh
zachowuje się tak samo .
W pierwotnym pytaniu powiedziałem, że to błąd w parserze Basha. Czy to jest [Aktualizacja: tak ] Odpowiedni tekst z POSIX (wszystkie z definicji Shell Command Language), który mogę znaleźć to:
- §2.6.3 Zmiana polecenia :
W formularzu $ (polecenie) wszystkie znaki następujące po otwartym nawiasie do pasującego nawiasu zamykającego stanowią polecenie. Do polecenia można użyć dowolnego poprawnego skryptu powłoki , z wyjątkiem skryptu składającego się wyłącznie z przekierowań, który daje nieokreślone wyniki.
- §2.7.4 Dokument tutaj :
Jeżeli cytowana jest jakakolwiek część słowa , separator należy utworzyć poprzez usunięcie cudzysłowu ze słowem , a wierszy dokumentu tutaj nie należy rozszerzać.
- §2.2.1 Znak ucieczki (ukośnik odwrotny) :
Jeśli <nowa linia> następuje po <lashlash>, powłoka interpretuje to jako kontynuację linii. <backlash> i <newline> należy usunąć przed podzieleniem danych wejściowych na tokeny.
- §2.3 Rozpoznawanie tokenów :
Kiedy gramatyka io_here zostanie rozpoznana przez gramatykę (patrz Gramatyka powłoki ), jeden lub więcej kolejnych wierszy bezpośrednio po następnym tokenie NEWLINE tworzy treść jednego lub więcej dokumentów tutaj i zostanie przeanalizowany zgodnie z zasadami zawartymi w niniejszym- dokument .
Gdy nie przetwarza io_here , powłoka rozbija dane wejściowe na tokeny, stosując pierwszą obowiązującą regułę poniżej do następnego znaku na wejściu. ...
...
- Jeżeli bieżącym znakiem jest <odwrotny ukośnik>, pojedynczy cudzysłów lub podwójny cudzysłów i nie jest on cytowany, będzie to miało wpływ na cytowanie kolejnych znaków aż do końca cytowanego tekstu. Zasady cytowania są w sposób opisany w Cytowanie . Podczas rozpoznawania tokena nie dokonuje się w rzeczywistości żadnych podstawień, a token wynikowy powinien zawierać dokładnie znaki, które pojawiają się na wejściu (z wyjątkiem łączenia <nowej linii>), niezmodyfikowane, w tym wszelkie osadzone lub obejmujące cytaty lub operatory podstawienia, od końca do końca cytowanego tekstu.
Moją interpretacją tego jest to, że wszystkie znaki po, $(
aż do zakończenia )
zawierają skrypt powłoki, dosłownie; pojawia się dokument tutaj, więc przetwarzanie dokumentu tutaj następuje zamiast zwykłej tokenizacji; dokument tutaj ma następnie cudzysłów, co oznacza, że jego treść jest przetwarzana dosłownie; i postać ucieczki nigdy do niej nie wchodzi. Widzę jednak argument, że ten przypadek po prostu nie został rozwiązany i oba zachowania są dopuszczalne. Możliwe, że pominąłem też jakiś odpowiedni tekst.
- Czy ta sytuacja jest wyjaśniona gdzie indziej?
- Na czym powinien polegać (w teorii) przenośny skrypt?
- Czy szczególne traktowanie zapewniane przez którąkolwiek z tych powłok (Bash 3.2 / Bash 4.3 / wszyscy inni) jest wymagane przez standard? Zakazany? Dozwolony?
echo "$x"
, ale jakikolwiek sposób sprawdzania zmiennej działa. Edytowałem tę linię na dole.
$(...)
czymkolwiek to wyjście ... Teraz, uruchamiając polecenie w twoim przykładzie w podpowłoce (in bash
), generuje oczekiwany wynik. Dopiero po przekształceniu go w substytucję polecenia zwija „ghi” i „jkl”. To jest błąd imo