Shell POSIX: `$` perde il suo significato speciale se è l'ultimo carattere di una parola?


17

Su cenere, trattino e bash, quando corro

$ echo ab$

ritorna

ab$

Questo comportamento è specificato da POSIX o è solo una convenzione comune nelle shell conformi a POSIX? Non ho trovato nulla nella pagina POSIX Shell Command Language che menzioni questo comportamento.


4
La domanda migliore è "non $ guadagnare un significato speciale se è l'ultimo carattere in una parola?" Non esiste un singolo significato speciale assegnato a $; è usato per introdurre espansioni multiple, ma distinte, come l'espansione dei parametri ${...}, la sostituzione dei comandi $(...)e le espressioni aritmetiche $((...)). Alcune shell introducono contesti aggiuntivi, come kshla variante di sostituzione dei comandi x=${ echo foo; echo bar;}(che differisce dallo standard $(...)non eseguendo i comandi in una subshell).
Chepner,

@chepner Ti andrebbe di valutare la differenza di opinione tra Issac e Michael Homer? Le loro risposte si contraddicono esplicitamente a vicenda
Harold Fischer il

1
Sono d'accordo con l'interpretazione di Michael Homer; la shell non inizia nemmeno a preoccuparsi delle espansioni fino al completamento dell'analisi, quindi nella singola parola ab$non è seguito alcun carattere $, sia che sia stato "seguito" da un carattere nullo nella stringa di input originale o da uno spazio in un caso come echo ab$ foo; lo spazio bianco non quotato originale è stato riconosciuto e scartato dopo l'analisi.
Chepner,

Risposte:


10

$non ha un significato speciale per sé (tentativo echo $), solo quando combinato con l'altro carattere dopo formatura e un'espansione, per esempio $var(o ${var}), $(util), $((1+2)).

Il $ottiene la sua "speciale", cioè come la definizione di un'espansione nello standard POSIX nella sezione token di riconoscimento :

Se il carattere corrente non è citato $o `, la shell deve identificare l'inizio di tutti i candidati per l'espansione dei parametri, la sostituzione dei comandi o l'espansione aritmetica dalle loro sequenze introduttive di caratteri non quotati: $o ${, $(o `, e $((, rispettivamente. La shell deve leggere input sufficienti per determinare l'estremità dell'unità da espandere ( come spiegato nelle sezioni citate). Durante l'elaborazione dei caratteri, se vengono trovati nidificati all'interno della sostituzione casi di espansioni o quotazioni, la shell li elabora in modo ricorsivo nel modo specificato per il costrutto trovato. I caratteri trovati dall'inizio della sostituzione fino alla fine, consentendo qualsiasi ricorsione necessaria per riconoscere i costrutti incorporati, devono essere inclusi non modificati nel token del risultato, inclusi eventuali operatori o virgolette di sostituzione incorporati o che racchiudono. Il token non deve essere delimitato entro la fine della sostituzione.

Quindi, se $non forma un'espansione, entrano in vigore altre regole di analisi:

Se il carattere precedente faceva parte di una parola, il carattere corrente deve essere aggiunto a quella parola.

Quello copre la tua ab$corda.

Nel caso di un solitario $(la "nuova parola" sarebbe di $per sé):

Il carattere corrente viene utilizzato come inizio di una nuova parola.

Il significato della parola generata contenente $un'espansione non standard è esplicitamente definito come non specificato da POSIX.

Si noti inoltre che $è l'ultimo carattere in $$, ma che anche questa è la variabile che contiene il PID della shell corrente. In bash, !$può invocare un'espansione della cronologia (l'ultimo argomento del comando precedente). Quindi, in generale, no, $non è privo di significato alla fine di una parola non quotata, ma alla fine di una parola non denota almeno un'espansione standard.


7

A seconda della situazione esatta, questo è esplicitamente non specificato (quindi le implementazioni possono fare come vogliono) o è necessario che accada come hai osservato. Nel tuo esatto scenario echo ab$, POSIX impone l'output "ab $" che hai osservato e non è specificato . Alla fine è disponibile un breve riepilogo di tutti i diversi casi.

Ci sono due elementi: prima il tokenismo in parole e poi l'interpretazione di quelle parole.


tokenizzazione

La tokenizzazione POSIX richiede che a $che non sia l'inizio di una valida espansione di parametro , sostituzione di comando o sostituzione aritmetica sia considerata una parte letterale del WORDtoken in costruzione. Questo perché la regola 5 ("Se il carattere corrente non è citato $o `, la shell deve identificare l'inizio di qualsiasi candidato per l'espansione dei parametri, la sostituzione dei comandi o l'espansione aritmetica dalle loro sequenze introduttive di caratteri non quotati: $oppure ${, $(o `, e $((, rispettivamente" ) non si applica, in quanto nessuna di tali espansioni è praticabile lì. L'espansione dei parametri richiede la visualizzazione di un nome valido e un nome vuoto non è valido.

Dal momento che questa regola non è stata applicata, continuiamo a seguirla fino a quando non ne troviamo una. I due candidati sono # 8 ("Se il carattere precedente faceva parte di una parola, il carattere corrente deve essere aggiunto a quella parola.") E # 10 ("Il carattere corrente viene utilizzato come inizio di una nuova parola.") , che si applicano a echo a$e echo $rispettivamente.

C'è anche un terzo caso della forma echo a$+bche rientra nella stessa crack, poiché +non è il nome di un parametro speciale. Questo torneremo più tardi, poiché innesca diverse parti delle regole.

La specifica richiede quindi che $venga considerata sintatticamente una parte della parola, e può quindi essere ulteriormente elaborata in seguito.


Espansione delle parole

Dopo che l'analisi è stata analizzata in questo modo, con l'inserimento $nella parola, le espansioni di parole vengono applicate a ciascuna delle parole che sono state lette. Ogni parola viene elaborata singolarmente .

Si specifica che :

Se un '$' non quotato è seguito da un carattere che non è uno dei seguenti:

  • Un carattere numerico
  • Il nome di uno dei parametri speciali (vedere Parametri speciali )
  • Un primo carattere valido di un nome variabile
  • A <left-curly-bracket>('{')
  • UN <left-parenthesis>

il risultato non è specificato.

"Non specificato" è un termine particolare qui che significa che

  1. Una shell conforme può scegliere qualsiasi comportamento in questo caso
  2. Un conforme applicazione non può contare su un particolare comportamento

Nel tuo esempio, echo ab$il $ non è seguito da alcun carattere , quindi questa regola non si applica e il risultato non specificato non viene richiamato. Semplicemente non vi è alcuna espansione incitata da $, quindi è letteralmente presente e stampata.

Dove sarebbe applicabile è nel nostro terzo caso dall'alto: echo a$+b. Qui $è seguito da +, il che non è un numero, parametro speciale ( @, *, #, ?, -, $, !, o 0), avviare di una variabile nome (sottolineatura o un alfabetica dal set di caratteri portatile ), o di una delle staffe. In questo caso, il comportamento non è specificato: una shell conforme è autorizzata a inventare un parametro speciale chiamato +per espandere , e un'applicazione conforme non dovrebbe supporre che la shell non lo faccia . La shell potrebbe fare anche qualcos'altro che gli piace, inclusa la segnalazione di un errore.

Ad esempio, zsh, incluso nella sua modalità POSIX, interpreta $+bcome "è bimpostato variabile " e sostituisce 1 o 0 al suo posto. Allo stesso modo ha estensioni per ~e =. Questo è un comportamento conforme.

Un altro posto in cui ciò potrebbe accadere è echo "a$ b". Ancora una volta, la shell è autorizzata a fare ciò che desidera e tu, come autore dello script, dovresti sfuggire $se vuoi un output letterale. In caso contrario, potrebbe funzionare, ma non puoi fare affidamento su di esso. Questa è la lettera assoluta del disciplinare, ma non credo che questo tipo di granularità sia stato inteso o considerato.


In sintesi

  • echo ab$: output letterale, completamente specificato
  • echo a$ b: output letterale, completamente specificato
  • echo a$ b$: output letterale, completamente specificato
  • echo a$b: espansione del parametro b, completamente specificata
  • echo a$-b: espansione del parametro speciale -, completamente specificato
  • echo a$+b: comportamento non specificato
  • echo "a$ b": comportamento non specificato

Per una $alla fine di una parola, si è permesso di fare affidamento sul comportamento e deve essere trattato in senso letterale e passato al echocomando come parte della sua tesi. Questo è un requisito di conformità sulla shell.


I commenti non sono per una discussione estesa; questa conversazione è stata spostata in chat .
terdon

@MichaelHomer Sarebbe echo $anche letterale e completamente specificato?
Harold Fischer,

@HaroldFischer Sì
Michael Homer,

Dove vanno echo "$"e echo "a b$"cadono?
Harold Fischer
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.