Che cos'è la divisione delle parole? Perché è importante nella programmazione della shell?


16

Mi sto confondendo il ruolo svolto dalla divisione delle parole zsh. Non sono stato esposto a questo concetto durante la programmazione in C, Python o MATLAB, e questo ha suscitato il mio interesse sul perché la suddivisione delle parole sembra essere qualcosa di specifico per la programmazione della shell.

Ho già letto della divisione delle parole su questo e altri siti prima, ma non ho trovato una chiara spiegazione del concetto. Wikipedia ha una definizione di suddivisione delle parole ma non sembra avere riferimenti su come si applica alle shell Unix.

Ecco un esempio della mia confusione in zsh:

Nelle FAQ di Z Shell , ho letto quanto segue:

3.1: Perché $vardove var="foo bar"non fare ciò che mi aspetto?

Nella maggior parte dei derivati ​​della shell Bourne, le variabili a più parole come quelle var="foo bar" vengono divise in parole quando passate a un comando o utilizzate in un for foo in $varciclo. Per impostazione predefinita, zsh non ha questo comportamento: la variabile rimane intatta. (Questo non è un bug! Vedi sotto.) L'opzione SH_WORD_SPLITesiste per fornire compatibilità.

Tuttavia, nel manuale Z Shell , ho letto quanto segue:

SH_WORD_SPLIT (-y) <K> <S>

Fa sì che la divisione dei campi venga eseguita su espansioni di parametri non quotate. Nota che questa opzione non ha nulla a che fare con la suddivisione delle parole. (Vedi Espansione parametri.)

Perché dice che nonSH_WORD_SPLIT ha nulla a che fare con la suddivisione delle parole? La suddivisione delle parole non è esattamente ciò di cui si tratta?

Risposte:


21

Le prime shell avevano un solo tipo di dati: stringhe. Ma è comune manipolare elenchi di stringhe, in genere quando si passano più nomi di file come argomenti a un programma. Un altro caso d'uso comune per la suddivisione è quando un comando genera un elenco di risultati: l'output del comando è una stringa, ma i dati desiderati sono un elenco di stringhe. Per memorizzare un elenco di nomi di file in una variabile, inseriresti degli spazi tra loro. Quindi uno script di shell come questo

files="foo bar qux"
myprogram $files

chiamato myprogramcon tre argomenti, poiché la shell ha diviso la stringa $filesin parole. All'epoca, gli spazi nei nomi dei file erano proibiti o ampiamente considerati Not Done.

La shell Korn introdotto array: è possibile memorizzare una lista di stringhe in una variabile. La shell Korn è rimasta compatibile con la shell Bourne allora consolidata, quindi le espansioni variabili nude hanno continuato a subire la divisione delle parole e l'uso di array ha richiesto un certo sovraccarico sintattico. Scriveresti lo snippet sopra

files=(foo bar qux)
myprogram "${files[@]}"

Zsh aveva array sin dall'inizio e il suo autore ha optato per un design del linguaggio più sano a spese della compatibilità con le versioni precedenti. In zsh (in base alle regole di espansione predefinite) $varnon viene eseguita la suddivisione delle parole; se si desidera memorizzare un elenco di parole in una variabile, si intende utilizzare un array; e se vuoi davvero dividere le parole, puoi scrivere $=var.

files=(foo bar qux)
myprogram $files

In questi giorni, gli spazi nei nomi dei file sono qualcosa che devi affrontare, sia perché molti utenti si aspettano che funzionino, sia perché molti script vengono eseguiti in contesti sensibili alla sicurezza in cui un utente malintenzionato può avere il controllo dei nomi dei file. Quindi la suddivisione automatica delle parole è spesso una seccatura; quindi il mio consiglio generale di usare sempre virgolette doppie, cioè scrivere "$foo", a meno che tu non capisca perché hai bisogno di dividere le parole in un caso d'uso particolare. (Nota che anche le espansioni variabili nude sono soggette a globbing.)


Grazie Gilles, questo è davvero utile! È corretto dire che la suddivisione in parole approssimative delle parole converte le stringhe del modulo "word1 word2 word3"in liste / matrici del modulo "word1" "word2" "word3"? Ho anche aggiornato l'OP con una specifica fonte di confusione in zsh.
Amelio Vazquez-Reina,

1
@intrpc "La suddivisione in parole" non si divide in parole in linguaggio naturale ma in $IFScaratteri. Quindi "divisione del campo" è un nome migliore. Ma la "suddivisione delle parole" è spesso usata per questo concetto nella letteratura shell. La documentazione di zsh sta frugando in parole.
Gilles 'SO- smetti di essere malvagio' il

1
Vedi anche rc(la shell plan9, anch'essa trasferita su Unix) per un design ancora migliore di zsh quando si tratta di variabili e array.
Stéphane Chazelas,

3

La suddivisione delle parole non è specifica per la shell.

La maggior parte dei programmi che necessitano di analizzare l'immissione di testo utilizza come prima fase una sorta di suddivisione delle parole. Viene fatto prima di identificare da queste "parole", numeri, operatori, stringhe, token e qualsiasi entità simile che devono elaborare.

Ciò che è specifico con le shell è che devono costruire correttamente l'elenco degli argomenti dei comandi chiamati (C argc / argv, python sys.argv), incluso passare argomenti con spazi incorporati, argomenti vuoti, delimitatori personalizzati e così via. Molte shell usano la variabile IFS per consentire una certa flessibilità lì.


3

In questo caso specifico di Zsh, la divisione delle parole è definita in modo leggermente diverso dalla divisione dei campi.

Considera prog a b c, passerà in tre argomenti, indipendentemente da come hai impostato IFS. Questa è la divisione delle parole .

Se lo fai A="a b c"; prog $A, passerà in tre argomenti se IFSinclude spazio o un argomento in caso contrario. Questa è la divisione del campo .

Le definizioni qui sono sottili. Ciò che il documento Zsh sta cercando di dire è che, anche se disabiliti quell'opzione, prog a b cotterrai comunque argomenti separati (che è quello che le persone si aspettano sempre).


1
Bart Schaefer, uno sviluppatore zsh di lunga data, conferma che è davvero il significato previsto di quel testo .
Stéphane Chazelas,
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.