Variabili d'ambiente vs parametri posizionali
Prima di iniziare a discutere il $INTEGER
tipo di variabili, dobbiamo capire cosa sono realmente e in che modo differiscono dalle variabili di ambiente. Variabili come i $INTEGER
cosiddetti parametri posizionali. Questo è descritto nello standard POSIX (Portable Operating System Interface), sezione 2.1 (enfasi sulla miniera):
- La shell esegue una funzione (vedere Comando definizione funzione), integrata (vedi Utilità integrate speciali), file eseguibile o script, fornendo i nomi degli argomenti come parametri posizionali numerati da 1 a n e il nome del comando (o nel caso di una funzione all'interno di uno script, il nome dello script) come parametro posizionale numerato 0 (vedere Ricerca ed esecuzione dei comandi).
Al contrario, variabili come $HOME
e $PATH
sono variabili di ambiente. La loro definizione è descritta nella sezione 8 della norma :
Le variabili d'ambiente definite in questo capitolo influiscono sul funzionamento di più utility, funzioni e applicazioni. Esistono altre variabili d'ambiente che interessano solo utilità specifiche. Le variabili d'ambiente che si applicano a una singola utility sono definite come parte della descrizione dell'utility.
Nota la loro descrizione. I parametri posizionali devono apparire davanti a un comando, ad es command positional_arg_1 positional_arg_2...
. Sono pensati per essere forniti dall'utente per dire al comando cosa fare specificamente. Quando lo fai echo 'Hello' 'World'
, stamperà le stringhe Hello
e World
, perché questi sono parametri posizionali su echo
- le cose su cui vuoi echo
operare. Ed echo
è costruito in modo tale da comprendere i parametri posizionali come stringhe da stampare (a meno che non siano uno dei flag opzionali come -n
). Se lo fai con un comando diverso, potrebbe non capire cosa Hello
eWorld
è perché forse si aspetta un numero. Si noti che i parametri posizionali non sono "ereditati": un processo figlio non è a conoscenza dei parametri posizionali del genitore se non è passato esplicitamente al processo figlio. Spesso vedi che i parametri posizionali vengono passati con gli script wrapper - quelli che forse controllano l'istanza esistente di un comando o aggiungono ulteriori parametri posizionali al comando reale che verrà chiamato.
Al contrario, le variabili di ambiente sono destinate a influenzare più programmi. Sono variabili d' ambiente , perché sono impostate al di fuori del programma stesso (più su questo di seguito). Alcune variabili di ambiente come HOME
o PATH
hanno un formato specifico, un significato specifico e significheranno lo stesso per ciascun programma. HOME
La variabile avrà lo stesso significato sia per l'utilità esterna che per /usr/bin/find
la shell (e, di conseguenza, per uno script): è la directory home del nome utente in cui viene eseguito il processo. Si noti che le variabili ambientali possono essere utilizzate per tenere conto del comportamento specifico del comando, ad esempioUID
la variabile di ambiente può essere utilizzata per verificare se lo script viene eseguito con privilegi di root o meno e ramificare di conseguenza azioni specifiche. Le variabili di ambiente sono ereditabili: i processi figlio ottengono una copia dell'ambiente del genitore. Vedi anche Se i processi ereditano l'ambiente del genitore, perché dobbiamo esportare?
In breve, la distinzione principale è che le variabili di ambiente sono impostate al di fuori del comando e non sono pensate per essere variate (di solito), mentre i parametri posizionali sono cose che devono essere elaborate dal comando e cambiano.
Non solo concetti di shell
Quello che ho notato dai commenti è che stai mescolando terminali e shell, e ti consiglierei davvero di leggere su terminali reali che una volta erano dispositivi fisici. Al giorno d'oggi, il "terminale" a cui ci riferiamo in genere, quella finestra con sfondo nero e testo verde è in realtà un software, un processo. Terminal è un programma che esegue una shell, mentre shell è anche un programma ma quello che legge ciò che si digita per eseguire (ovvero, se si tratta di shell interattiva; le shell non interattive sono script e sh -c 'echo foo'
tipi di invocazioni). Maggiori informazioni sulle conchiglie qui .
Questa è una distinzione importante, ma anche importante riconoscere che il terminale è un programma e quindi aderisce alle stesse regole di ambiente e parametri posizionali. Il tuo gnome-terminal
quando avviato guarderà la tua SHELL
variabile di ambiente e genererà la shell predefinita appropriata per te, a meno che non specifichi qualche altro comando con -e
. Diciamo che ho cambiato la mia shell predefinita in ksh
- gnome-terminal verrà quindi generato ksh
invece di bash
. Questo è anche un esempio di come l'ambiente viene utilizzato dai programmi. Se io dico in modo esplicito gnome-terminal
con -e
eseguire shell specifica - lo farà, ma non sarà permanente. Al contrario, l'ambiente dovrebbe essere per lo più inalterato (ne parleremo più avanti).
Come puoi vedere, le variabili di ambiente e di posizione sono entrambe proprietà di un processo / comando, non solo di shell. Quando si tratta di script di shell, seguono anche il modello impostato dal linguaggio di programmazione C. Prendiamo ad esempio la main
funzione C che in genere sembra
int main(int argc, char **argv)
, dove argc
c'è il numero di argomenti della riga di comando ed argv
è effettivamente un array di parametri della riga di comando, e poi c'è la environ
funzione (su Linux che è man -e 7 environ
) di accedere a cose come il percorso della directory home dell'utente, l'elenco delle directory in PATH
cui possiamo cercare eseguibili, ecc. Anche gli script di shell sono modellati in modo simile. Nella terminologia shell, abbiamo parametri posizionali $1
, $2
e così via, mentre $#
certo numero di parametri posizionali. Che dire $0
? Questo è il nome dell'eseguibile stesso, che è di nuovo modellato dal linguaggio di programmazione C - argv[0]
sarebbe il nome del tuo "eseguibile". E questo è abbastanza vero per la maggior parte dei linguaggi di programmazione e scripting .
Shell interattive vs non interattive
Una delle cose che ho già accennato è la distinzione tra shell interattive e non interattive . Il prompt in cui si digitano i comandi: interattivo, interagisce con l'utente. Al contrario, quando si dispone di uno script di shell o si esegue bash -c''
che non è interattivo.
Ed è qui che la distinzione diventa importante. La shell che si esegue già è un processo, che è stato generato con parametri posizionali (per la bash
shell di login è uno "... il cui primo carattere dell'argomento zero è un -, o uno è iniziato con l'opzione --login." ( Riferimento ) )
Al contrario, gli script e le shell avviati con l' -c
opzione possono trarre vantaggio $1
e $2
argomenti. Per esempio,
$ bash -c 'echo $1; stat $2' sh 'Hello World' /etc/passwd
Hello World
File: '/etc/passwd'
Size: 2913 Blocks: 8 IO Block: 4096 regular file
Device: 801h/2049d Inode: 6035604 Links: 1
Access: (0644/-rw-r--r--) Uid: ( 0/ root) Gid: ( 0/ root)
Access: 2017-08-12 14:48:37.125879962 -0600
Modify: 2017-08-12 14:48:37.125879962 -0600
Change: 2017-08-12 14:48:37.137879811 -0600
Birth: -
Si noti che ho usato anche sh
lì, perché una piccola stranezza di -c
opzione è quella di prendere il primo parametro posizionale e assegnarlo, a $0
differenza del solito essere un nome del programma.
Un'altra cosa che è importante notare è che i parametri posizionali sono quelli che io chiamo "framable". Notate come, inizialmente abbiamo lanciato bash
i propri parametri posizionali, ma quei parametri posizionali sono diventati parametri a echo
e stat
. E ogni programma lo capisce a modo suo. Se dessimo stat
una stringa Hello World
e non ci fosse alcun file Hello World
, si produrrebbe un errore; bash
la tratta come una semplice stringa ma si stat
aspetta che quella stringa sia un nome file esistente. Al contrario, tutti i programmi concorderebbero sul fatto che la variabile d'ambiente HOME
è una directory (a meno che il programmatore non la abbia codificata in modo irragionevole).
Possiamo pasticciare con variabili d'ambiente e parametri posizionali?
Tecnicamente, possiamo fare confusione con entrambi, ma non dovremmo fare confusione con le variabili di ambiente, mentre spesso dobbiamo fornire parametri posizionali. Possiamo eseguire comandi in shell con anteporre una variabile, ad esempio:
$ hello=world bash -c 'echo $hello'
world
Possiamo anche posizionare le variabili nell'ambiente semplicemente usando export variable=value
dalla shell o dallo script. Oppure possiamo eseguire un comando con un ambiente completamente vuoto con env -c command arg1 arg2
. Tuttavia, in genere non è consigliabile scherzare con l'ambiente, in particolare utilizzando variabili maiuscole o sovrascrivendo variabili di ambiente già esistenti. Si noti che è raccomandato sebbene non sia uno standard.
Per i parametri posizionali, il modo di impostarli è ovvio, basta anteporli al comando, ma ci sono anche modi per impostarli in altro modo , oltre a cambiare l'elenco di tali parametri tramite shift
comando.
In conclusione, lo scopo di questi due è diverso ed esistono per un motivo. Spero che la gente abbia avuto un'idea di questa risposta, ed è stato divertente leggerlo come è stato per me scrivere questa risposta.
Nota sul comando set
Il set
comando, secondo il manuale, si comporta in questo modo (dal manuale di bash, enfasi aggiunta):
Senza opzioni, il nome e il valore di ciascuna variabile di shell vengono visualizzati in un formato che può essere riutilizzato come input per l'impostazione o il ripristino delle variabili attualmente impostate.
In altre parole, set
esamina le variabili specifiche della shell, alcune delle quali si trovano nell'ambiente, ad esempio HOME
. Al contrario i comandi gradiscono env
e printenv
osservano la variabile d'ambiente effettiva con cui viene eseguito un comando. Si veda anche questo .
export 3
trasformarsi$3
in una variabile di ambiente. Non puoiunset 3
; e non puoi assegnare$3
un nuovo valore usando3=val
.