Qual è la struttura dei dati di $ @ nella shell?


13

Di solito usiamo $@per rappresentare tutti gli argomenti tranne $ 0. Tuttavia, non so quale sia la struttura dei dati $@.

Perché si comporta diversamente $*quando si include tra virgolette doppie, qualcuno potrebbe darmi una spiegazione a livello di interprete?

Può essere ripetuto per il ciclo, quindi sembra essere un array. Tuttavia, può anche fare eco interamente con semplici echo $@, se si tratta di un array, verrà mostrato solo il primo elemento. A causa della limitazione della shell, non riesco a scrivere più codice di esperimento per eseguirlo.

Differenza tra questo post : questo post mostra come $@si comporta diversamente $*. Ma mi chiedo il tipo di dati di $@. Shell come linguaggio di interpretazione, come Python, dovrebbe rappresentare i dati secondo una serie di tipi fondamentali. O in altre parole, voglio sapere come $ @ è stato archiviato nella memoria del computer.

È una stringa, una stringa multilinea o un array?

Se si tratta di un tipo di dati univoco, è possibile definire una variabile personalizzata come istanza di questo tipo?



@Haxiel, non credo, ho scritto la loro differenza in fondo al mio post.
David

Saresti meglio servito testando la differenza nell'output con printf '%s\n' "$@"e printf '%s\n' "$*". L' echoutilità genera semplicemente i suoi argomenti, indipendentemente dal fatto che siano uno o più. Entrambi sono array (di stringhe), ma si comportano in modo diverso quando vengono citati due volte. Se una delle due fosse una stringa a più righe, allora non sarebbero in grado di memorizzare stringhe a più righe (cosa che possono). Non è chiaro quale problema si sta tentando di risolvere.
Kusalananda

2
La tua domanda equivale a chiedere che cos'è una @varvariabile in Perl, in termini di memoria sottostante. Dal punto di vista di un normale programma Perl, non importa davvero, a parte il fatto che è accessibile come un array / elenco (e il fatto che ci sono contesti in cui è previsto un elenco).
Kusalananda

Risposte:


16

È iniziato come un trucco nella shell Bourne. Nella shell Bourne, la divisione delle parole IFS è stata eseguita (dopo la tokenizzazione) su tutte le parole nel contesto dell'elenco (argomenti della riga di comando o le parole su cui si ripetono i forloop). Se tu avessi:

IFS=i var=file2.txt
edit file.txt $var

Questa seconda linea sarebbe tokenised in 3 parole, $varsarebbe stato ampliato, e dividere + glob sarebbe stato fatto su tutte e tre le parole, così si finirebbe in esecuzione edcon t, f, le.txt, f, le2.txtcome argomenti.

La citazione di parti di ciò impedirebbe la divisione + glob. La shell Bourne inizialmente ricordava quali personaggi venivano citati impostando internamente l'ottavo bit (che cambiò più tardi quando Unix divenne pulito a 8 bit, ma la shell fece ancora qualcosa di simile per ricordare quale byte era citato).

Entrambi $*e $@sono stati la concatenazione dei parametri posizionali con spazio in mezzo. Ma c'è stata un'elaborazione speciale di $@quando all'interno delle doppie virgolette. Se $1contenuto foo bare $2contenuto baz, "$@"si espanderebbe in:

foo bar baz
^^^^^^^ ^^^

(con la ^s sopra che indica quale dei personaggi ha l'ottavo bit impostato). Dove è stato citato il primo spazio (con l'ottavo bit impostato) ma non il secondo (quello aggiunto tra le parole).

Ed è la suddivisione IFS che si occupa di separare gli argomenti (supponendo che il carattere dello spazio sia $IFScome è di default). È simile a come è $*stato ampliato nel suo predecessore la shell Mashey (a sua volta basata sulla shell Thomson, mentre la shell Bourne è stata scritta da zero).

Questo spiega perché nella shell Bourne inizialmente si "$@"sarebbe espanso nella stringa vuota invece di nulla quando l'elenco dei parametri posizionali era vuoto (con cui si doveva aggirare ${1+"$@"}), perché non manteneva i parametri posizionali vuoti e perché "$@"non non funziona quando $IFSnon contiene il carattere spaziale.

L'intenzione era quella di essere in grado di passare la lista di argomenti alla lettera ad un altro comando, ma che non funzionava correttamente per la lista vuota, per gli elementi vuoti o quando $IFSnon conteneva spazio (i primi due problemi furono infine risolti nelle versioni successive ).

La shell Korn (su cui si basa la specifica POSIX) ha modificato questo comportamento in alcuni modi:

  • La suddivisione IFS viene eseguita solo sul risultato di espansioni non quotate (non su parole letterali come edito file.txtnell'esempio sopra)
  • $*e $@vengono uniti con il primo carattere $IFSo spazio quando $IFSè vuoto tranne quello per un quotato "$@", quel joiner non è citato come nella shell Bourne, e per un quotato "$*"quando IFSè vuoto, i parametri posizionali vengono aggiunti senza separatore.
  • ha aggiunto il supporto per gli array, e con ${array[@]} ${array[*]}reminiscenze di Bourne $*e $@ma a partire dall'indice 0 invece di 1, e scarso (più simile agli array associativi) il che significa che $@non può davvero essere trattato come un array ksh (confronta con csh/ rc/ zsh/ fish/ yashdove $argv/ $*sono normali array).
  • Gli elementi vuoti vengono conservati.
  • "$@"quando $#è 0 ora si espande nel nulla anziché nella stringa vuota, "$@"funziona quando $IFSnon contiene spazi tranne quando IFSè vuoto. Un non quotato $*senza caratteri jolly si espande in un argomento (in cui i parametri posizionali sono uniti con lo spazio) quando $IFSè vuoto.

ksh93 risolto i restanti pochi problemi sopra. In ksh93, $*e si $@espande all'elenco dei parametri posizionali, separato indipendentemente dal valore di $IFS, e quindi ulteriormente diviso + globbed + parentesi espansa nei contesti di elenco, $*unito al primo byte (non carattere) di $IFS, "$@"nei contesti di elenco si espande all'elenco dei parametri posizionali, indipendentemente dal valore di $IFS. In un contesto non di elenco, come in var=$@, $@viene unito con spazio indipendentemente dal valore di $IFS.

bashLe matrici sono progettate dopo quelle ksh. Le differenze sono:

  • nessuna parentesi graffa-espandi in caso di espansione non quotata
  • primo carattere di $IFSanziché di byte
  • alcune differenze di maiuscole / minuscole come l'espansione di $*quando non quotato in un contesto non di elenco quando $IFSè vuoto.

Mentre le specifiche POSIX erano piuttosto vaghe, ora specifica più o meno il comportamento bash.

È diverso dalle normali matrici in ksho bashin quella:

  • Gli indici iniziano da 1 invece di 0 (tranne in "${@:0}"cui include $0(non un parametro posizionale, e nelle funzioni ti dà il nome della funzione o meno a seconda della shell e di come è stata definita la funzione)).
  • Non puoi assegnare elementi singolarmente
  • non è scarso, non puoi disinserire gli elementi singolarmente
  • shift può essere utilizzato.

In zsho yashdove gli array sono array normali (non sparsi, gli indici iniziano da uno come in tutti gli altri shell ma ksh / bash), $*viene trattato come un array normale. zshha $argvcome alias per esso (per compatibilità con csh). $*è lo stesso di $argvo ${argv[*]}(argomenti uniti al primo carattere di $IFSma ancora separati in contesti di lista). "$@"come "${argv[@]}"o "${*[@]}"}subisce la speciale elaborazione in stile Korn.


8

Tuttavia, non so quale sia la struttura dei dati $@.

È un parametro speciale che si espande ai valori dei parametri posizionali ... Ma questo è pignolo sulla terminologia.

Possiamo visualizzare i parametri posizionali come parti di $@, quindi ha un numero di elementi distinti ( $1, $2...), a cui è possibile accedere in modo indipendente e che sono nominati da numeri naturali consecutivi. Questo lo rende qualcosa che di solito viene chiamato un array.

La sintassi è un po 'strana, però, e persino limitata. Non è possibile modificare singolarmente un singolo elemento dell'array. Invece, tutto deve essere impostato in una volta. (È possibile utilizzare set -- "$@" fooper aggiungere un valore o set -- "${@:1:2}" foo "${@:3}"per aggiungere un valore nel mezzo. Ma in entrambi i casi è necessario scrivere l'intero elenco risultante.)

Perché si comporta diversamente $*quando si include tra virgolette doppie,

Perché sono definiti per comportarsi diversamente.

Tuttavia, può anche fare eco interamente con semplici echo $@, se si tratta di un array, verrà mostrato solo il primo elemento.

Se intendi il fatto che a=(foo bar asdf); echo $aprodurrà solo l'output foo, questo è principalmente una stranezza della sintassi della shell e il fatto che le matrici denominate in stile ksh sono state create dopo i parametri posizionali e $@. Plain $aè lo stesso di quello ${a[0]}che ha il significato retrocompatibile di un singolo valore scalare, indipendentemente dal fatto che asia una matrice o una semplice variabile scalare.

Il @segno che fa riferimento all'intera lista è stato riutilizzato con array denominati in questo modo "${a[@]}"è possibile ottenere l'intera lista. Rispetto alle matrici nominate, con $@, le parentesi graffe e le parentesi non necessarie e il nome vengono semplicemente ignorati.

O in altre parole, voglio sapere come $@archiviato nella memoria del computer.

Dipende dall'implementazione, dovrai cercare il codice sorgente di ogni particolare shell a cui tieni.

È una stringa, una stringa multilinea o un array?

Un array, per lo più. Sebbene diversi dagli array denominati in stile ksh, dal momento che possono avere interi non negativi arbitrari come indici, non solo quelli consecutivi come con $@. (Cioè, un array può essere sparso, e hanno ad esempio gli indici 1, 3e 4, con 0e 2mancanti. Questo non è possibile con i parametri posizionali.)

Non è una singola stringa, poiché può essere espansa in elementi distinti e anche chiamare le righe degli elementi non è corretto, poiché qualsiasi variabile regolare o uno dei parametri posizionali (elementi di $@) può contenere anche nuove righe.

Se si tratta di un tipo di dati univoco, è possibile definire una variabile personalizzata come istanza di questo tipo?

No. Ma le matrici nominate sono probabilmente più utili comunque.


1
+1. TL: DR $@non è una struttura di dati, è una delle poche funzioni / operatori per espandere la struttura di dati dei parametri posizionali.
Peter Cordes,
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.