Inferno - Copertina - Corso Linux |
Articolo
E' bene evitare di generalizzare pensando che vi sia un unico modo attraverso il quale il sistema possa dialogare con l'utente. Esistono diversi tipi di shell, e storicamente si distinguono tre categorie: le Bourne shell, le C shell e le Korn shell.
Linux riprende questa suddivisione dai sistemi Unix suoi predecessori, e addirittura aumenta il numero di interfacce a disposizione presentandone delle evoluzioni sia per quanto riguarda l'interazione con l'utente che le possibilità di scripting. Gli utenti di Linux di default hanno a disposizione, come in tutti i sistemi GNU, la bash (Bourne Again Shell, uno dei soliti giochi di parole tipici dei programmatori) una versione modificata della Bourne, che incorpora alcune delle caratteristiche più utili di C e Korn shell.
In questo articolo esamineremo, oltre la bash, altre due interfacce di tipo avanzato: la tcsh (Tenex C Shell), ovviamente della categoria delle C shell, e la zsh, di tipo Korn, che sebbene meno conosciute hanno a loro vantaggio una buona versatilità e la possibilità di creare script evoluti grazie al loro linguaggio di programmazione interno.
Oltre ad esse, Linux presenta una serie molto ricca di altre shell: ne abbiamo di dimensioni ridotte, come ad esempio ash o kiss, che proprio per la loro minima occupazione di risorse e la loro semplicità, vengono utilizzate in casi particolari come per i dischetti di installazione delle varie distribuzioni di Linux; ci sono poi interfacce speciali, come ad esempio lsh che fornisce comandi compatibili con quelli del DOS, utile per i principianti, oppure tclsh che è un vero e proprio interprete tcl. Insomma, vi è quasi una soluzione per ogni esigenza.
Per storico si intende la possibilità di richiamare i comandi che sono stati memorizzati dall'interfaccia, senza dovere riscriverli tutte le volte. Questa comoda opzione consente di introdurre anche all'interno di linee di comando successive tutto ciò che è stato inviato precedentemente alla shell e che questa ha provveduto a memorizzare in sequenza.
Tutte le shell hanno un set di caratteri che assumono dei significati speciali e consentono di effettuare alcune operazioni che influenzano l'interpretazione della linea di comando: i meta caratteri che consentono l'espansione dei nomi dei file (* ?), i caratteri per la reindirizzo e le pipe (<, > e |), gli spazi, le virgolette e gli apici, l'ampersand (&), il punto e virgola, il dollaro ($); questi ed altri sono considerati speciali, riservati, e non possono essere inseriti all'interno di una linea di comando senza le opportune precauzioni.Per evitare che questi caratteri vengano interpretati è necessario farli precedere da un backslash (\), che è anch'esso un carattere speciale e quindi va raddoppiato, se lo si vuole inserire in una linea di comando senza che venga a sua volta interpretato (\\).
Un altro modo per evitare l'interpretazione dei caratteri consiste nel racchiuderli all'interno delle virgolette (") o degli apici (' - attenzione, non gli apici inversi); il modo in cui essi operano è leggermente differente a seconda della shell utilizzata, ma indicativamente il loro utilizzo è questo:
- le virgolette (") proteggono i caratteri speciali in esse inclusi dall'interpretazione consentendo la sostituzione delle variabili
gli apici (') hanno la stessa funzione delle virgolette ma impediscono la sostituzione delle variabili.
Gli alias sono delle utili abbreviazioni con le quali è possibile ridefinire comandi con molte opzioni, difficili da ricordare o lunghi da scrivere. In genere gli alias sono definiti nei file di inizializzazione della shell e vanno definiti con la seguente sintassi:Se il valore dell'alias è formato da più parole, queste vanno messe tra apici; ad esempio, in bashbash alias nome=valore tcsh alias nome valore zsh alias nome=valore
alias ls='ls --color -F'
consente di visualizzare i diversi tipi di file evidenziandoli con differenti colori.Se gli alias risultano utili per ridefinire comandi discretamente complessi, maggiore flessibilità viene offerta dalle funzioni, ovvero insiemi di comandi raggruppati sotto una singola "etichetta" che consentono di aumentare la modularità degli script. Ovviamente, come in generale per tutti i casi riguardanti la definizione del comportamento di una shell, la sintassi per la definizione di una funzione varia leggermente a seconda della shell usata: ad esempio ecco come vengono definite in Bash e Zsh:
Bash [ function ] nomefunzione () {listacomandi; } Zsh function nomefunzione [()] [term] {listacomandi} word () [term] {listacomandi} word () [term] comandodove term è uno o più caratteri di newline o un punto e virgola.
Gli utenti di sistemi operativi Unix devono avere ben presente i concetti di standard input e standard output: quando un programma scrive qualcosa sullo schermo, sta usando lo standard output, o stdout; mentre se voi date al programma dei comandi da tastiera, state usando lo standard input, o stdin.Normalmente, un comando di sistema, come ad esempio "ls" accetta delle informazioni provenienti dallo standard input e restituisce i risultati del suo operato tramite stdout, ovvero in genere il monitor; in più, i programmi possono utilizzare un ulteriore dispositivo chiamato standard error, o stderr, in genere collegato allo schermo, che consente di comunicare gli eventuali errori avvenuti nel corso della loro esecuzione.
Sia stdin che stdout possono essere facilmente manipolati, in modo da concatenare più comandi insieme, da redirigere l'output in un file, o da acquisire l'input da un file.
Scrivere su un file l'output di un comando, che normalmente andrebbe sullo schermo, è abbastanza semplice e molto comodo per consultare le informazioni che esso mette a disposizione, o condividerle con altre persone. Il carattere che consente di redirigere lo stdout su un file è >. Ad esempio
crea il file file.txt che visualizza l'elenco dei file presenti nella directoryls /etc > file.txt
/etc
. Come abbiamo già detto, non solo è possibile salvare su disco le informazioni che andrebbero normalmente a schermo, ma è anche fattibile l'operazione inversa, leggendo da file gli argomenti che normalmente andrebbero scritti sulla linea di comando. In questo caso il carattere da utilizzare è <:In questo caso cat ci consente di visualizzare sullo schermo il contenuto del filecat < /etc/passwd
/etc/passwd
: in questo modo redirigiamo lo stdin del programma su file.Non tutti i comandi accettano però l'input dallo stdin: per scoprire è possibile utilizzare questo metodo è bene consultare la pagina di man relativa, dato che in essa è sempre presente questo tipo di informazione.
Complicando ancora un po' le cose, vediamo come è possibile redirigere l'output di un comando come input di un altro, utilizzando le pipe. In questo caso il carattere che ci consente questa operazione è |:
Intercalando i due programmi (ls /usr/bin | more
ls
emore
) con il carattere di pipe inviamo il flusso di informazioni proveniente dal primo (lo stdout di ls) in input al secondo (more), ottenendo in questo caso una migliore visualizzazione del contenuto della directory/usr/bin
, dato che la lista ottenuta non scorrerà senza controllo sullo schermo ma verrà fermata quando lo avrà riempito e ripartirà con la pressione di un tasto.Quando si utilizza la redirezione dell'output va fatta attenzione, perché se viene specificato un file già esistente, questo viene sovrascritto, perdendo le informazioni che vi erano state immesse in precedenza. Per avere una scrittura "incrementale" è meglio utilizzare la modalità append che consente di scrivere l'output di un comando in un file, aggiungendolo alla fine dello stesso:
o, addirittura, è possibile prendere più linee di input da linea di comando, fino ad una determinata parola, come nell'esempio seguente:ls /usr/bin >>lista
In questo caso possiamo inviare via mail più di una riga senza uscire dalla linea di comando. La shell manda al comando cat tutte le linee inserite finché non trova una riga in cui sia contenuta solo la parola EOF; l'output del comando cat viene poi mandato in pipe a mail. Il tutto con poche righe in bash!piccinino:~$cat << EOF | mail eugenia >Questa è una mail sperimentale >C'è anche una seconda linea >EOF
Una shell Unix è in grado di gestire più processi contemporaneamente consentendo, fra l'altro, di manipolare la loro esecuzione fornendo delle priorità di interazione con l'utente. Un programma può, in poche parole, essere posto in background, sullo sfondo, o in foreground, ovvero in primo piano: basti pensare ai processi come a degli strati che si sovrappongono, di cui solo ciò che sta più in alto (in primo piano, appunto) è visibile.Quando si dà un comando, il programma corrispondente viene eseguito in primo piano, e ci preclude l'uso della shell. Il comando in esecuzione può essere però sospeso (con un segnale di stop, di solito
Crtl-Z
) e mandato in background con bg; in questo modo è possibile continuare a lavorare, riportando in seguito in primo piano il programma con fg.Per avviare un processo direttamente in background si può fare seguire il comando dal segno "&": in questo modo l'elaborazione passa direttamente in background lasciando all'utente il controllo della shell. Attenzione, pero': nella zsh il controllo dei job può essere disattivato.
In questo caso un comando seguito da & ha l'output inviato direttamente in /dev/null, e quindi viene perso.
Si può avere un elenco dei processi attivi tramite il comando jobs; per indicare il processo cui ci riferisce bisogna anteporre un % al numero di job (che si vede utilizzando il comando jobs).
Quindi, per fare un esempio, volendo mandare in background il primo processo della shell dobbiamo usare il comando
bg %1
Spesso è possibile influenzare il comportamento di alcuni programmi e della shell stessa configurando opportunamente alcune variabili, definite locali o d'ambiente a seconda del loro utilizzo. Brevemente, le variabili locali sono proprie della shell in cui sono state definite, e non vengono usate da nessun processo da essa creato, mentre le variabili d'ambiente vengono passate dai processi stessi ai loro figli. Alcune variabili d'ambiente, a loro volta, sono ereditate dal processo che crea la shell, in genere login, mentre altre vengono definite nei suoi file di inizializzazione o dall'utente, direttamente dalla linea di comando. Una variabile d'ambiente molto importante èPATH
che, analogamente a quanto succede in DOS, indica le directory in cui vengono ricercati i file da eseguire; in questo modo è possibile lanciare un programma senza doverne indicare il percorso, se questo è presente nel path.Una istanza tipica di PATH potrebbe essere questa:
Notate che con PATH viene indicata la variabile, mentre con $PATH il suo valore, che nell'esempio è stato istanziato conPATH=$PATH:~/bin
~/bin
. In questo esempio, al valore già esistente diPATH
,$PATH
, viene aggiunta la directory~/bin
.Riferendoci ancora alle variabili va detto che normalmente esse vengono considerate locali; per renderle d'ambiente vanno "esportate", cioè va fatto in modo che siano valide anche per i processi figli del processo della shell. In bash ed in zsh la procedura da seguire è la seguente:
* si definisce la variabile PATH=$PATH:~/bin * la si esporta export PATH oppure, in una sola linea: export PATH=$PATH:~bin
Nella tcsh si usa invece il comando set per le variabili normali, e setenv per quelle di ambiente. Ad esempio:imposta il pager di default a less (al posto di more, il pager predefinito, less permette anche di tornare indietro utilizzando le frecce).setenv PAGER less
A volte è comodo poter sostituire i comandi, ovvero assegnare ad una variabile l'output di un comando, o sostituire l'output ad una stringa contenente il comando stesso. In questo caso il carattere utilizzato per operare la sostituzione, in tutte le shell esaminate, è l'apice inverso (`
).Facciamo un esempio:
Un altro metodo per sostituire i comandi usato da alcune shell è $(comando); questo metodo permette di inserire la stessa operazione vista in precedenza in modo più semplice e con minori rischi di errore, ma può essere applicato solo in bash e zsh, non in tcsh.locate `which bash` è equivalente a locate /bin/bash dato che which bash rende /bin/bash
Spesso capita di voler cancellare un'intera serie di file i cui nomi contengono una sequenza tipica, di volerli copiare, oppure di volerci compiere una qualsiasi operazione. Specificare su linea di comando ogni nome può diventare lungo e noioso, specialmente se sono coinvolti parecchi file; meglio allora utilizzare dei caratteri speciali per l'espansione dei nomi dei file, o "caratteri jolly", che consentono di indicare contemporaneamente su una stessa linea i nomi di più file.I meta caratteri usati da tutte le shell esaminate sono:
Anche in questo caso anteponendo un*
espande zero o più caratteri?
espande un solo carattere[abc]
espande un carattere dell'insieme (a, b o c)[a-z]
espande un carattere nell'intervallo a-z^
nega la corrispondenza successiva (es. [^abc])~
espande la home directory dell'utente\
al meta carattere ne disabilita la funzione.Altre shell utilizzano anche dei meta caratteri aggiuntivi: la zsh, ad esempio, consente di indicare un intervallo di interi con <x-y> o di selezionare solo i file di un certo tipo (si usa (/) per indicare le directory, (@) per i link e così via). Dato che differenti shell possono avere diversi caratteri speciali, è bene consultare i documenti relativi all'interfaccia utilizzata per avere informazioni più dettagliate che qui non possiamo approfondire per motivi di spazio.
Maggiore interesse forse riveste la possibilità offerta dalle shell esaminate di completare automaticamente i nomi dei comandi ed i nomi dei file. Se si hanno dei nomi molto lunghi, è possibile inserirne solo una parte significativa e premere "tab" per vedere magicamente completarsi sotto i nostri occhi tutta la scritta; se invece viene fornita una parte non significativa, premendo due volte "tab", in bash, verrà fornito un elenco di file o comandi che iniziano con le lettere da noi inserite.
Oltre alla possibilità di completare i nomi dei file e dei comandi, le shell permettono anche di modificare la linea di comando stessa usando le combinazioni di tasti proprie degli editor. Le associazioni dei tasti sono in genere quelle che un utente di emacs o di vi si aspetterebbe; ad esempio in bash per cancellare il carattere sul cursore si usa
Ctrl-D
, per andare in fondo alla linea si usaCtrl-E
e così via, sempre che sia impostata la modalità emacs, che è quella di default.Alcune shell permettono anche di correggere gli errori di battitura, ovvero caratteri invertiti, mancanti o in eccesso, automaticamente o dando un comando: digitando in maniera non corretta il nome di una directory è possibile vedere corretto il nostro errore e passare comunque alla directory desiderata.
Per rendere meno pesante il lavoro su Linux è bene imparare la lista dei comandi interni della shell da utilizzare, comandi che possono essere usati sia interattivamente che all'interno di script. Ci sono, come noto a tutti, comandi abbastanza semplici come
cd
, ma accanto a questi vi sono strumenti più complessi come quelli relativi alla gestione dei loop, che possono semplificare notevolmente la vita dell'utente medio. Pensiamo, ad esempio, alla situazione tipica in cui bisogna decomprimere un certo numero di archivi tar.gz e in seguito cancellarli. Usando una semplice linea di comando di bash, ad esempio, è possibile automatizzare il tutto:Questa riga può essere letta in questo modo: a ciascun elemento dell'output del comando ls applicare il comando tar, poi cancellare il file. Semplice e molto efficace. Da notare che utilizzando i punto e virgola è possibile concatenare più comandi su una stessa linea.for i in `ls *.tar.gz`; do tar xzf $i ; rm $i ; done
I file di configurazione sono uno degli aspetti più importanti della shell: qui vanno definite le variabili d'ambiente, gli alias e le funzioni che influenzeranno il modo in cui l'utente si interfaccia con il sistema operativo. Non solo, qui possono essere indicati inoltre i processi da eseguire all'avvio della stessa, siano essi programmi o comandi interni.Normalmente i file di configurazione sono tre: uno, valido globalmente, risiede nella directory
/etc
, mentre gli altri due, uno per le shell di login e uno per quelle interattive, si trovano nelle home directory degli utenti e sono liberamente modificabili.Qui di seguito riportiamo i nomi dei file di inizializzazione delle varie shell, con il loro uso.
Bash /etc/profile
contiene i comandi da eseguire all'avvio di una shell di login, ed è comune a tutti gli utenti ~/.bash_profile
contiene i comandi da eseguire all'avvio di una shell di login per ciascun utente. ~/.bash.login
usati se ~/.bash_profile
non esiste, per compatibilità~/.profile
~/.bashrc
contiene i comandi da eseguire all'avvio di una qualsiasi shell interattiva non di login ~/.bash_logout
contiene i comandi da eseguire al momento del logout. All'avvio di una shell non interattiva bash legge la variabile
ENV
, la espande e carica il file che indica come.$ENV
. Se bash è richiamata come sh, cerca di imitarne il comportamento il più fedelmente possibile, e quindi legge solo i file/etc/profile
e~/.profile
per le shell di login, e nessun altro.
Tcsh /etc/csh.cshrc
file di sistema per shell interattive /etc/csh.login
file di sistema per shell di login ~/.tcshrc
file per le shell interattive ~/.cshrc
usato in sostituzione di ~/.tcshrc se questo non esiste ~/.login
file per le shell di login /etc/csh.logout
file di sistema usato al logout ~/.logout
file personalizzabile dall'utente usato al logout
Zsh /etc/zshenv
file di sistema per tutte le invocazioni della shell $ZDOTDIR/.zshenv
per tutte le invocazioni della shell $ZDOTDIR/.zprofile
simile a zlogin ma usato prima di .zshrc $ZDOTDIR/.zshrc
per le shell interattive $ZDOTDIR/.zlogin
per le shell di login $ZDOTDIR/.zlogout
al logout Se la variabile
$ZDOTDIR
non viene indicata specificamente, il suo valore è pari a$HOME
, cioè è la home directory dell'utente.
Se non siete soddisfatti della shell di sistema potete sempre scegliere quello che fa per voi ed indicare a Linux la vostra scelta modificando il fileCiò che conta, e che spesso sfugge all'utente alle prime armi, è che non sempre una shell è quell'ambiente ostico che appare alla prima installazione. Conoscere la shell che si sta utilizzando è il primo passo verso la creazione di un'interfaccia realmente amichevole, user friendly non perché presenti icone e finestre ma perché realmente consente di lavorare meglio e più efficacemente./etc/passwd
. Dando un'occhiata a questo file si può notare che alcuni utenti "di sistema" hanno come shell un programma particolare: ad esempio sync ha la shell/bin/sync
, e quindi al suo collegamento viene eseguito il programmasync
. La stessa cosa si potrebbe fare per rendere disponibili ad utenti non di root alcuni servizi senza che questi implichino particolari privilegi. Ad esempio, creando un utente shutdown con una shell/sbin/shutdown
si consente a chiunque di effettuare una procedura di arresto di sistema semplicemente collegandosi con lo username e la password adeguati. Gli esempi potrebbero continuare citando, per esempio, la possibilità di creare utenti senza diritto di login, sostituendo ad una shell reale una/bin/false
o una/bin/passwd
, nel caso si volesse lasciare la possibilità di cambiare la password.
Ristampato con il permesso di Inter.net
Inferno - Copertina - Corso Linux |