\

Aqui temos um livro livre e completo sobre Shell

Os sedentos do "saber livre" são muito benvindos.

Você está aqui: TWikiBar > BatePapos > TWikiBarChiacchiere010
Controles: EDITAR ANEXAR MAIS MAIS ALTERACOES IMPRIMIR - Última Atualização: [06 Mar 2013 - V.3]

Chiacchiere da Bar Parte X



     - Allora, amico, ti ho dato un esercizio semplice oppure no? Una cosina facile facile...

     - Dai test che ho fatto e d'accordo con ciò che mi hai insegnato sulla sostituzione di parametri, penso di dover apportare qualche altro cambiamento alle funzioni che abbiamo sviluppato per rendere il loro uso più generico possibile, esattamente come mi hai detto di fare. Vuoi dare un'occhiata?

     - Beh, se ti ho chiesto di fare qualcosa è perché voglio essere sicuro che stai imparando, ma aspetta un attimo, tutto a suo tempo!

     - Chico! Porta due birre, una senza schiuma!

     - Adesso sì, fammi vedere ciò che hai fatto.

     - Ok. Oltre a ciò che mi hai chiesto, mi son accorto che nel programma che richiamava la funzione dovrebbero essere predefiniti la riga nella quale appare il messaggio e il numero di colonne. Detto questo, ho inserito due righe – nelle quali ho utilizzato la sostituzione di parametri – in modo tale che, nel caso in cui una di queste variabili non sia valorizzata, la funzione stessa provveda a farlo. La riga del messaggio dovrebbe essere la terzultima a partire dalla fine dello schermo e il totale delle colonne dovrebbe essere ottenuto tramite il comando tput colonne. Prova a dare un'occhiata:

$ cat domanda.funz # La funzione riceve 3 parametri in questo ordine: # $1 – Messaggio da mostrare sullo schermo # $2 - Valore da accettare come risposta di default # $3 - L'altro valore accettato # Supponendo che $1=Accetti?, $2=s e $3=n, la riga # sottostante immette in Msg il valore "Accetti? (S/n)" TotColonne=${TotColonne:-$(tput colonne)} # Se non era definito, adesso lo è RigaMesg=${RigaMesg:-$(($(tput lines)-3))} # Idem Msg="$1 (`echo $2 | tr a-z A-Z`/`echo $3 | tr A-Z a-z`)" LungMsg=${#Msg} Col=$(((TotColonne - LungMsg) / 2)) # Per centrare Msg nella riga tput cup $RigaMesg $Col read -n1 -p "$Msg " SN SN=${SN:-$2} # Se vuota immette il valore di default in SN SN=$(echo $SN | tr A-Z a-z) # L'output di SN sarà in minuscolo tput cup $RigaMesg $Col; tput el # Cancella il messaggio dallo schermo

     - Mi piace, hai anticipato ciò che stavo per chiederti. Giusto per concludere il discorso sulla sostituzione di parametri, osserva che la leggibilità del codice è orribile ma la performance, cioè la velocità di esecuzione, è ottima. Poiché le funzioni sono faccende molto personali, visto che ognuno utilizza le proprie e quasi non hanno bisogno di manutenzione, io scelgo sempre la performance.

     - Oggi abbandoniamo quella roba barbosa di cui abbiamo parlato l'altra volta e torniamo alla logica evitando le cose da imparare a memoria, ma ti ricordo che tutto ciò che ti ho mostrato l'ultima volta qui al Bar di Chico resta assolutamente valido perché può aiutarti a risolvere parecchi problemi, per cui tieni da parte i tovaglioli sui quali abbiamo scarabocchiato perché prima o poi ti saranno molto utili.

Il comando eval

     - Ti assegnerò un problema che dubito risolverai:

$ var1=3 $ var2=var1

     - Date queste due variabili, voglio che tu mi dica come posso elencare, riferendomi solo a $var2, il valore di $var1 (3).

     - Facile, basta scrivere:

    echo $`echo $var2`

     - Nota che ho messo echo $var2 tra apici (`): in questo modo avrà priorità di esecuzione e darà come risultato var1, quindi echo$var1 darà come risultato 3...

     - Davvero? Mandalo in esecuzione e vediamo se è giusto.

$ echo $`echo $var2` $var1

     - Ah! Cos'è successo? Il mio ragionamento sembrava del tutto logico...

     - Il tuo ragionamento era logico, il problema è che ti sei dimenticato di una delle prime cose di cui ti ho parlato qui al Bar. Adesso te la ripeto: la Shell usa il seguente ordine per risolvere una linea di comandi:

  • Risolve i redirezionamenti;
  • Sostituisce le variabili con i rispettivi valori;
  • Risolve e sostituisce i metacaratteri;
  • Manda in esecuzione la linea così preparata.

In base a questo, arrivati alla fase di risoluzione delle variabili che, come ho detto, è antecedente all'esecuzione, l'unica variabile esistente era $var2, quindi la tua soluzione ha come output $var1. Il comando echo ha identificato tale output come una stringa e non come una variabile.

Problemi di questo tipo sono relativamente frequenti e sarebbero insolubili se non esistesse l'istruzione eval, la cui sintassi è:

    eval cmd

dove cmd è una qualsiasi riga di comando che puoi addirittura eseguire direttamente nel prompt del terminale. Quando anteponi eval, accade che la Shell tratta cmd come se i suoi dato fossero parametri di eval, quindi eval esegue la riga ricevuta passandola alla Shell: in questo modo cmd viene praticamente elaborato due volte.

Detto questo, se eseguissimo il comando che hai proposto preceduto da eval, otterremmo l'output sperato. Osserva:

$ eval echo $`echo $var2` 3

L'esempio potrebbe anche essere strutturato così:

$ eval echo \$$var2 3

Nella prima elaborazione la barra inversa (\) è eliminata e $var2 è risolto producendo come output var1, nella seconda rimane soltanto echo $var1, il cui output è il risultato sperato.

Adesso inserisco un comando dentro var2:

$ var2=ls

Proviamo a eseguirlo:

$ $var2 10perpag1.sh hello2.sh elencanzone logaut.sh 10perpag2.sh confuso elencartista inviamsg.funz 10perpag3.sh contpar.sh elencartista3 monbg.sh hello1.sh inserutnte loggato

Adesso inseriamo in var2 quanto segue: ls $var1. Allo stesso modo, inseriamo l* in var1. Osserva:

$ var2='ls $var1' $ var1='l*' $ $var2 ls: $var1: No such file or directory $ eval $var2 elencanzone elencartista elencartista3 loggato logaut.sh

Ancora una volta, al momento della sostituzione delle variabili, $var1 non era ancora stato presentato alla Shell per la risoluzione: in tal modo, ci resta soltanto da eseguire il comando eval per i due passaggi necessari.

Una volta, un collega di un eccellente gruppo Shell Script, (brasiliano frown ) ha posto un quesito: voleva creare un menu che numerasse ed elencasse tutti i suoi file con estensione .sh e che, in base alla scelta dell'utente, fosse eseguito il programma corrispondente. La mia proposta fu la seguente:

$ cat creamenu #!/bin/bash # # Elenco che numera i programmi con estensione .sh presenti nella # directory corrente ed esegue quello scelto dall'utente # clear; i=1 printf "%11s\t%s\n\n" Opzione Programma CASE='case $opt in' for file in *.sh do printf "\t%03d\t%s\n" $i $file CASE="$CASE "$(printf "%03d)\t %s;;" $i $file) i=$((i+1)) done CASE="$CASE *) . erro;; esac" read -n3 -p "Inserisci l'opzione desiderata: " opt echo eval "$CASE"

Sembra complicato perché ho utilizzato molti printf per formattare lo schermo, ma è piuttosto semplice. Vediamo come funziona. Ho utilizzato il primo printf per l'intestazione, poi ho iniziato a montare dinamicamente la variabile $CASE, all'interno della quale, proprio alla fine, sarà eseguito un eval per lanciare il programma scelto. Osserva che all'interno del loop di for ci sono due printf: il primo serve a formattare lo schermo e il secondo per montare case (se prima del comando read si inserisce una linea contenente echo "$CASE", vedremo che il comando case montato all'interno della variabile è completamente indentato. Carino, vero? smile ). All'interno dell'output di for è stata aggiunta una riga alla variabile $CASE allo scopo di eseguire una funzione esterna che restituisca un messaggio di errore se è compiuta una scelta errata.

Proviamo a mandarlo in esecuzione per vedere l'output generato:

$ creamenu.sh Opzione Programma

001 10perpag1.sh 002 10perpag2.sh 003 10perpag3.sh 004 hello1.sh 005 hello2.sh 006 contpar.sh 007 creamenu.sh 008 logaut.sh 009 monbg.sh 010 leggipipe.sh 011 redirread.sh Inserisci l'opzione desiderata:

In questo programma sarebbe interessante inserire un'opzione di fine: per farlo è necessario inserire una riga dopo il loop di montaggio dello schermo e modificare la riga nella quale eseguiamo l'attribuzione finale del valore della variabile $CASE. Vediamo come si presenta:

$ cat creamenu #!/bin/bash # # Elenco che numera i programmi con estensione .sh presenti nella # directory corrente ed esegue quello scelto dall'utente # clear; i=1 printf "%11s\t%s\n\n" Opzione Programma CASE='case $opt in' for file in *.sh do printf "\t%03d\t%s\n" $i $file CASE="$CASE "$(printf "%03d)\t %s;;" $i $file) i=$((i+1)) done printf "\t%d\t%s\n\n" 999 "Fine del programma" # Riga inclusa CASE="$CASE 999) exit;; # Riga modificata *) ./erro;; esac" read -n3 -p "Inserisci l'opzione desiderata: " opt echo eval "$CASE"

Segnali di Processi

In Linux c'è una cosa chiamata segnale (signal). Esistono diversi segnali che possono essere inviati ai (o generato dai) processi in esecuzione. Adesso diamo un'occhiata ai segnali inviati ai processi: più avanti vedremo rapidamente i segnali generati dai processi.

Segnali assassini

Per inviare un segnale a un processo, utilizziamo normalmente il comando kill, la cui sintassi è:

    kill -sig PID

dove PID è l'identificatore del processo (Process IDentification ou Process ID). Oltre al comando kill, alcune sequenze di tasti possono generare sig. La tabella seguente mostra i segnali più importanti da monitorare:

Segnali Più Importanti
 15   SIGTERM  Quando ricevee un kill o un kill -TERM 
Segnale  Generato da:
0 EXIT  Fine normale del programa
1 SIGHUP  Quando ricevee un kill -HUP
2 SIGINT  Interruzione causata da (<CTRL+C>)
3 SIGQUIT  Interruziona causata da (<CTRL+\>)

Oltre a questi segnali, esiste il famigerato -9 o SIGKILL che, per il processo che lo riceve, equivale a mettere il dito sul pulsante di spegnimento del computer, fatto assolutamente indesiderabile poiché molti programmi devono “fare le pulizie” prima di terminare. Se la chiusura avviene nel modo previsto, cioè correttamente, è facile che tale pulizia avvenga: al contrario, se il programma termina bruscamente, possono accadere molte cose:

  • È possibile che, in un determinato periodo di tempo, il computer si ritrovi pieno di file di lavoro inutili
  • Il processore potrà essere rallentato da processi zombie e defunct generati da processi-figli privi del processo-padre;
  • É necessario liberare socket aperti per non lasciare client in stato di freeze;
  • Le banche-dati potranno essersi corrotte poiché i programmi che le gestiscono hanno bisogno di un certo tempo per scrivere i buffer sul disco (commit).

Per concludere, ci sono mille ragioni per non usare un kill con segnale -9 e per monitorare la fine anomala dei programmi.

Trap non intrappola

Per eseguire i controlli descritti in precedenza esiste il comando trap la cui sintassi è:

    trap "cmd1; cmd2; cmdn" S1 S2 ... SN

oppure

    trap 'cmd1; cmd2; cmdn' S1 S2 ... SN

dove i comandi cmd1, cmd2, cmdn saranno eseguiti nel caso in cui il programma riceva il segnale S1 S2 ... SN.

Le virgolette (") o gli apostrofi (') sono necessari nel caso in cui trap abbia più di un comando cmd associato. Ognuno dei cmd può anche essere una funzione interna, una funzione esterna oppure un altro script.

Per comprendere l'uso delle virgolette (") e degli apostrofi (') ricorreremo a un esempio che tratta un frammento di uno script che crea un ftp per un computer remoto ($RemoComp). L'utente di tale computer è $Tizio, la sua password $Segreto e sarà trasmesso il file contenuto in $File. Ipotizziamo anche che queste quattro variabili siano state ricevute tramite una precedente routine di lettura e che questo script sia utilizzato spesso da diversi utenti. Osserviamo questo pezzo di codice:

ftp -ivn $RemoComp << FineFTP >> /tmp/$$ 2>> /tmp/$$
    user $Tizio $Segreto
    binary
    get $File
FineFTP

Osserva che sia gli output dei dialoghi dell' ftp, sia gli errori trovati, sono redirezionati in /tmp/$$, costrutto piuttosto usuale per gli archivi temporanei utilizzati in script con più di un utente, poiché $$ è la variabile che contiene il numero del processo (PID), che è univoco, e con questo tipo di costruzione si evita che due o più utenti bisticcino per la proprietà e i diritti su un archivio.

Se questo ftp sia interrotto tramite un kill o un <CTRL+C> sicuramente lascerà robaccia sul disco. È esattamente questo il modo con il quel si usa più frequentemente il comando trap. Poiché questo è il frammento di uno script, dobbiamo scrivere, all'inizio e come primo comando, ciò che segue:

    trap "rm -f /tmp/$$ ; exit" 0 1 2 3 15

In questo modo, se si verifica una brusca interruzione (segnali 1, 2, 3 ou 15) prima della chiusura del programma (il comando exit all'interno di trap) oppure la fine naturale dello stesso (segnale 0), il file /tmp/$$ sarà rimosso.

Se la riga dei comandi di trap non contenesse l'istruzione exit, al termine dell'esecuzione della stessa il flusso del programma tornerebbe al punto in cui si trovava quando ha ricevuto il segnale che ha originato l'esecuzione di trap.

Questo trap potrebbe essere diviso in due parti nel seguente modo:

    trap "rm -f /tmp/$$" 0
    trap "exit" 1 2 3 15

Quando riceve uno di questi segnali, il programma termina generando un segnale 0 che rimuove il file. Se termina normalmente, anche il segnale è generato e rm è eseguito.

Nota anche che la Shell legge la riga dei comandi una prima volta quando trap è interpretato (ed è per questo che di solito è collocato all'inizio del programma) e una seconda volta quando uno dei segnali elencato è ricevuto. Per questo, nell'ultimo esempio il valore di $$ è sostituito nel momento in cui il comando trap è letto al primo passaggio, poiché le virgolette (") non proteggono il simbolo del dollaro ($) dall'interpretazione della Shell.

Se vogliamo che la sostituzione avvenga soltanto al momento della ricezione del segnale, il comando deve essere inserito fra apostrofi ('). In questo modo, alla prima interpretazione di trap, la Shell non vede il simbolo del dollaro ($), quindi gli apostrofi (') sono rimossi e finalmente la Shell può sostituire il valore della variabile. In questo caso, la riga apparirebbe così:

    trap 'rm -f /tmp/$$ ; exit' 0 1 2 3 15

Immaginiamo due casi: abbiamo due script che chiameremo script1 (la cui prima riga è un trap )e script2 (quest'ultimo sarà mandato in esecuzione dal primo). Essendo due processi distinti, essi avranno PID distinti.

  • 1º Caso: L' ftp si trova all'interno di script1
    In questo caso, l'argomento del comando trap deve essere inserito tra virgolette (") perché, se si verifica un'interruzione (<CTRL+C> oppure <CTRL+\>) in script2, la riga è interpretata solo in questo momento e il PID di script2 è diverso da quello presente in /tmp/$$ (non dimenticare che $$ è la variabile che contiene il PID del processo attivo);

  • 2º Caso: L' ftp precedente si trova all'interno di script2
    In questo caso, l'argomento del comando trap deve essere inserito fra apostrofi (') perché, se l'interruzione avviene durante l'esecuzione di script1, il file non è creato, se invece avviene durante l'esecuzione di script2, il valore di $$ è il PID di questo processo, il quale coincide con quello di /tmp/$$.

Il comando trap, quando eseguito senza argomenti, elenca i segnali monitorati all'interno dell'ambiente, assieme alla riga di comando che sarà utilizzata quando quei segnali saranno ricevuti.

Se la riga dei comandi di trap è nulla (vuota) vuol dire che i segnali specificati devono essere ignorati appena sono ricevuti. Per esempio, il comando:

    trap "" 2

indica che il segnale di interruzione (<CTRL+C>) deve essere ignorato. Nel caso citato, non si vuole che l'esecuzione sia interrotta. Nell'ultimo esempio puoi notare che il primo argomento deve essere specificato affinché il segnale sia ignorato, e non è equivalente a scrivere quanto segue, il cui scopo è riportare il segnale 2 al suo stato normale (default):

    trap 2

Se si ignora un segnale, tutte le Sottoshell lo ignoreranno. Pertanto, se indichi quale azione deve essere compiuta quando si riceve un segnale, tutte le Sottoshell eseguiranno quell'azione quando riceveranno il segnale, ossia i segnali sono automaticamente esportati. Riguardo al segnale che abbiamo mostrato (segnale 2), ciò significa che le Sottoshell saranno chiuse.

Immagina di eseguire il comando:

    trap "" 2

e di eseguire subito una Sottoshell, che eseguirà un altro script come una Sottoshell. Se si genera un segnale di interruzione, esso non avrà effetto ne sulla Shell principale ne sulla Sottoshell richiamata dal segnale poiché tutte le Sottoshell lo ignoreranno.

Un'altro modo di riportare un segnale al suo valore di default è scrivere quanto segue:

    trap - segnale

Nella korn shell (ksh) non esiste l'opzione -s del comando read per leggere una password. Di solito utilizziamo il comando stty con l'opzione -echo che blocca la comparsa di messaggi sullo schermo fino a quando non ci si imbatte in un stty echo che ripristina il massaggio. Detto questo, se stessimo utilizzando l'interprete ksh, la lettura della password dovrebbe essere fatta nel modo seguente:

    echo -n "Password: "
    stty -echo
    read Password
    stty echo

Il problema in questo tipo di costrutti è che, se non conosce la password, l'utente probabilmente premerebbe <CTRL+C> o <CTRL+\> durante l'istruzione read per interrompere il programma e, se ciò si verificasse, quanto inserito in seguito non apparirebbe in alcun modo sullo schermo.Per evitare che questo accada, la soluzione migliore è scrivere:

    echo -n "Password: "
    trap "stty echo
          exit" 2 3
    stty -echo
    read Password
    stty echo
    trap 2 3

Per concludere l'argomento, apri una console e scrivi nel prompt quanto segue:

$ trap "echo È cambiata la grandezza della finestra" 28

Adesso prendi il mouse (arghh!!) e spostalo in modo tale da variare la grandezza della finestra corrente. Sorpreso? È la Shell orientata agli eventi... smile

Non potevo resistere a mostrarti un altro esempio piccolo piccolo. Adesso scrivi:

$ trap "echo sparita" 17

Poi immetti questo:

$ sleep 3 &

Hai appena creato una sottoshell che dormirà per tre secondi in background. Trascorso questo arco di tempo, riceverai il messaggio sparita, perché il segnale 17 è emesso ogni volta che l'esecuzione di una sottoshell termina.

Per riportare i due segnali ai loro valori di default scrivi:

$ trap 17 28

oppure

$ trap - 17 28

Abbiamo appena visto due segnali non importanti quanto quelli studiati prima, ma li registrerò comunque nella tabella seguente:

Signali Non Molto Importanti
  28     SIGWINCH     Variazione di grandezza della finestra grafica  
Segnale  Generato da:
  17     SIGCHLD     Fine di un processo figlio  

Bello questo comando, vero? Se scopri qualche caso interessante di uso dei segnali, per favore informami tramite e-mail perché la letteratura sull'argomento è piuttosto carente.

Comando getopts

Il comando getopts recupera opzioni e argomenti da un elenco di parametri secondo la sintassi POSIX.2, cioè lettere (o numeri) dopo un segno meno (-) seguiti da argomenti oppure senza alcun argomento; se sono soltanto lettere (oppure numeri), allora possono essere raggruppati. Puoi utilizzare questo comando per filtrare accuratamente opzioni e argomenti da passare ai tuoi script.

Sintassi:

    getopts stringadiopzioni nome

Stringadiopzioni deve esibire una stringa di caratteri con tutte le opzioni riconosciute dallo script, in modo tale che se esso riconosce le opzioni -a -b e -c, stringadiopzioni deve essere abc. Se vuoi che un'opzione sia seguita da un argomento, inserisci due punti (:) dopo la lettera, ad esempio a:bc. Ciò informa getopts che l'opzione -a ha la forma seguente:

    -a argomento

Normalmente il parametro è separato dall'opzione tramite uno o più spazi; tuttavia, getopts manipola anche parametri contigui all'opzione come nell'esempio sottostante:

    -aargomento

Stringadiopzioni non può contenere punti interrogativi (?).

Nome, presente nella riga esplicativa della sintassi, definisce una variabile che, a ogni esecuzione del comando getopts, riceverà l'opzione successiva dei parametri posizionali e la inserirà nella variabile nome.

Getopts inserirà un punto interrogativo (?) nella variabile definita in nome se incontrerà un'opzione non definita in stringadiopzioni o se non troverà l'argomento atteso da una determinata opzione.

Come sappiamo, ogni opzione passata da una riga di comandi ha un indice numerico, per cui la prima opzione sarà contenuta in $1, la seconda in $2, e così via. Quando a getopts è assegnata un'opzione, esso immagazzina l'indice del parametro che sarà processato subito dopo nella variabile OPTIND.

Quando un'opzione ha un argomento associato (indicato tramite : in stringadiopzion i), getopts immagazzina l'argomento nella variabile OPTARG. Se un'opzione non possiede alcun argomento o è rinvenuto l'argomento atteso, la variabile OPTARG sarà "uccisa" (unset).

Il comando conclude la sua esecuzione quando:

  • Trova un parametro che non inizia con il segno meno (-);
  • Il parametro speciale -- indica la fine delle opzioni;
  • Quando si genera un errore (ad esempio un'opzione non riconosciuta).

L'esempio seguente è puramente didattico e serve per mostrare, in una piccola porzione di codice, il pieno utilizzo del comando.

$ cat getoptst.sh #!/bin/sh

# Eseguilo così: # # getoptst.sh -h -Pstampante file1 file2 # # e nota che sono mostrate le informazioni riguardanti tutte le opzioni # # La stringa 'P:h' dice che l'opzione -P è un'opzione complessa # e richiede un argomento, e che h è un'opzione semplice e non richiede # argomenti.

while getopts 'P:h' OPT_LETTERA do echo "getopts ha reso la variabile OPT_LETTERA uguale a '$OPT_LETTERA'" echo " OPTARG eh '$OPTARG'" done used_up=`espr $OPTIND - 1` echo "Fornisco i primi \$OPTIND-1 = $used_up argomenti" shift $used_up echo "Ciò che è rimasto della riga di comando è '$*'"

Per comprendere meglio l'esempio, proviamo a eseguirlo come suggerito nell'intestazione:

$ getoptst.sh -h -Pstampante file1 file2 getopts ha reso la variabile OPT_LETTERA uguale a 'h' OPTARG è '' getopts ha reso la variabile OPT_LETTERA uguale a 'P' OPTARG è 'stampante' Fornisco i primi $OPTIND-1 = 2 argomenti Ciò che è rimasto della riga di comando è 'file1 file2'

In questo modo, senza troppi sforzi, ho separato le opzioni con i relativi argomenti, lasciando da parte solamente i parametri inseriti dall'utente affinché siano trattati in seguito.

Nota che, se avessimo scritto la riga di comando con l'argomento (stampante) separato dall'opzione (-P), il risultato sarebbe stato esattamente lo stesso , tranne che per $OPTIND poiché, in questo caso specifico, esso identifica un insieme di tre opzioni/argomenti mentre nel precedente ne identificava soltanto due. Osserva:

$ getoptst.sh -h -P stampante file1 file2 getopts ha reso la variabile OPT_LETRA uguale a 'h' OPTARG eh '' getopts ha reso la variabile OPT_LETRA uguale a 'P' OPTARG eh 'stampante' Fornisco i primi $OPTIND-1 = 3 argomenti Ciò che è rimasto della riga di comando è 'file1 file2'

Osserva che, come evidenziato nell'esempio seguente, se inseriamo un'opzione non valida, la variabile $OPT_LETTERA assumerà come valore (?) e $OPTARG sarà "cancellata" (unset).

$ getoptst.sh -f -Pstampante file1 file2 # L'opzione -f noin è valida ./getoptst.sh: illegal option -- f getopts ha reso la variabile OPT_LETTERA uguale a '?' OPTARG eh '' getopts ha reso la variabile OPT_LETTERA uguale a 'P' OPTARG eh 'stampante' Fornisco i primi $OPTIND-1 = 2 argomenti Ciò che è rimasto della riga di comando è 'file1 file2'

     - Dimmi una cosa: non avresti potuto utilizzare case per evitare getopts?

     - Avrei potuto, ma a quale scopo? I comandi esistono per essere utilizzati... L'esempio che ti ho fatto è solo didattico, ma immagina un programma che accetti molte opzioni ma i cui parametri possano essere o non essere contigui alle rispettive opzioni: sarebbe un case infernale, mentre con getopts basterebbe seguire quanto fatto in precedenza.

     - In effetti... Guardando il problema da questo punto di vista devo darti ragione. Adesso sono stanco, mi hai ficcato in testa troppe cose nuove. Ci facciamo un'ultima bevuta o vuoi spiegarmi qualche altra particolarità della Shell?

     - Ne l'una ne l'altra, anch'io sono stanco ma oggi niente bicchiere della staffa perché sto per andare a fare lezione all' UniRIO, la prima università federale che offre corsi sull'uso del Software Libero ai propri studenti del corso di laurea in informatica.

Ma prima ti lascio un esercizio per farti spremere le meningi: quando cambi la grandezza dello schermo, al centro non appare, in modo dinamico, la quantità di righe e colonne. Bene! Voglio che tu faccia questo, con carattere inverso, utilizzando il linguaggio Shell.

     - Chico, portami il conto immediatamente! Conto fino a uno e se non è pronto scappo!


Licença Creative Commons - Atribuição e Não Comercial (CC) 2017 Pelos Frequentadores do Bar do Júlio Neves.
Todo o conteúdo desta página pode ser utilizado segundo os termos da Creative Commons License: Atribuição-UsoNãoComercial-PermanênciaDaLicença.