790 likes | 1.02k Views
La shell di Linux. Linux ha una varietà di shell differenti: Bourne shell (sh), C shell (csh), Korn shell (ksh), TC shell (tcsh), Bourne Again shell (bash).
E N D
La shell di Linux • Linux ha una varietà di shell differenti: • Bourne shell (sh), C shell (csh), Korn shell (ksh), TC shell (tcsh), Bourne Again shell (bash). • Sicuramente la shell più popolare è “bash”. Bash è la shell che è stata introdotta nel sistema operativo GNU. Bash è una shell sh-compatibile che incorpora utili caratteristiche della Korn shell (ksh) e della C shell (csh). • Bash è conforme allo standard IEEE POSIX P1003.2/ISO 9945.2 Shell and Tools. • Garantisce miglioramenti funzionali rispetto a sh sia per programmare che per l’uso interattivo.
Programming o Scripting ? • Bash non è soltanto un’eccellente interprete di comandi, ma un vero e proprio supporto per un linguaggio di script. Il linguaggio di script della shell permette di utilizzare le potenzialità della shell e di automatizzare un mucchio di compiti che richiederebbero altrimenti una grande quantità di comandi. • Differenza tra linguaggi di programmazione e linguaggi di script: • I linguaggi di programmazione sono in genere notevolmente più potenti e veloci dei linguaggi di script. I linguaggi di programmazione generalmente partono dal codice sorgente e vengono compilati in un eseguibile. Tale eseguibile non è facilmente portabile su differenti sistemi operativi. • Un linguaggio di script parte a sua volta dal codice sorgente, ma non viene compilato in un eseguibile. Piuttosto, un interprete legge le istruzioni nel file sorgente ed esegue ciascuna istruzione. I programmi interpretati sono in genere più lenti dei programmi compilati. Il vantaggio principale è che si può facilmente portare il file sorgente su ogni sistema operativo. Bash è un linguaggio di script. Altri esempio di linguaggi di script sono Perl, Lisp, e Tcl.
Il primo programma bash • Occorre sapere come usare un editor di testo. Ci sono due editor di testo principali in Linux: • vi (o vim), emacs (o xemacs). • Dunque lanciamo un editor di testo; ad esempio: • $ emacs & e digitiamo ciò che segue: • #!/bin/bashecho “Hello World” • La prima linea dice a Linux di utilizzare l’interprete bash per eseguire questo script. Lo chiameremo hello.sh. Ora rendiamo lo script eseguibile: • $ chmod 700 hello.sh • $ ls –l -rwx------ hello.sh
Il primo programma bash • Per eseguire il programma: • $ hello.sh -bash: hello.sh: command not found La directory home (in cui il comando hello.sh si trova) non si trova fra quelle elencate nella variabile d’ambiente PATH • echo $PATH :bin:/usr/bin:… Occorre specificare il path di hello.sh • $/home/lferrari/Scripts/hello.sh • $./hello.sh
Il secondo programma bash • Scriviamo un programma che copia tutti i files in una directory, e poi cancella la directory con tutto il suo contenuto. Ciò può essere fatto col seguente comando: • $ mkdir trash $ cp * trash$ rm -rf trash • Invece di essere costretti a digitare tutto ciò in modo interattivo nella shell, scriviamo uno script di shell: • $ cat > trash #!/bin/bash# this script deletes some files mkdir trash cp * trashrm -rf trash echo “Deleted all files!”
Variabili • Si possono usare le variabili come in ogni linguaggio di programmazione. I loro valori sono sempre memorizzati come stringhe, ma ci sono delle strutture nel linguaggio di shell che convertono le variabili in numeri per fare i calcoli. • Non c’è bisogno di dichiarare una variabile, il solo fatto di assegnarle un valore la crea automaticamente. • Esempio • #!/bin/bash STR=“Hello World!” echo $STR • La linea 2 crea una variabile detta STR e assegna la stringa "Hello World!" ad essa. Quindi il valore di questa variabile viene recuperato mettendo il '$' all’inizio.
Attenzione! • Il linguaggio della shell non tipizza (assegna un tipo a) le variabili. Ciò significa che una variabile può contenere dati numerici o alfabetici. • count=0 • count=Sunday • Cambiare il tipo di una variabile può generare confusione, sia per chi scrive lo script che per qualcuno che cerca di modificarlo, pertanto è raccomandato l’uso di un solo tipo di dati per ogni singola variabile all’interno di uno script. • \ è il carattere di escape di bash, e conserva il valore letterale del carattere che segue. • $ ls \* ls: *: No such file or directory
Virgolette singole e doppie • Quando si assegnano dati contenenti spazi o caratteri speciali, i dati devono essere racchiusi tra virgolette (singole o doppie). • Quando si usano virgolette doppie (partial quoting) per stampare a video una stringa di caratteri, ogni variabile verrà sostituita dal valore che essa assume in quel momento. • $ var=“test string” $ newvar=“Value of var is $var” $ echo $newvar Value of var is test string • L’uso di virgolette singole (full quoting) per visualizzare una stringa di caratteri non permette la risoluzione delle variabili. • $ var=’test string’ $ newvar=’Value of var is $var’ $ echo $newvar Value of var is $var
Esempi vari • $ pippo= pluto • $ pippo =pluto • $ ls [Pp]* • $ ls “[Pp]*” • $ ls ‘[Pp]*’ • $ var=“’(]\\{}\$\”” • $ echo $var • $ echo “$var” • $ echo ‘$var’ • $ echo \z # z • $ echo \\z # \z • $ echo ‘\\z’ # \\z errore Not resolved
Esempi vari $ pippo=cat $ echo “comando = \” $pippo \” “ comando =“ cat ” $ echo ‘comando = \” $pippo \” ‘ comando =\” $pippo \” $ echo ‘comando = ” $pippo ” ‘ comando =” $pippo “
Il comando export • Il comando exportinserisce una variabile nell’ambiente, così che essa sarà accessibile ai processi figli. Per esempio: • $ x=hello $ bash # Run a child shell. $ echo $x # Nothing in x. $ exit # Return to parent. $ export x $ bash $ echo $x hello # It's there. • Se il processo figlio modifica x, non verrà modificato il valore originale nel processo padre. Si verifichi tale fatto cambiando x nel modo seguente: • $ x=ciao $ exit $ echo $x hello
Variabili di ambiente • Ci sono due tipi di variabili: • Variabili locali • Variabili di ambiente • Le variabili di ambiente sono definite a livello di sistema e possono di norma essere reperite usando il comando env. Le variabili di ambiente contengono valori speciali. Ad esempio, • $ echo $SHELL /bin/bash $ echo $PATH /usr/X11R6/bin:/usr/local/bin:/bin:/usr/bin • Le variabili di ambiente sono definite in /etc/profile,/etc/profile.d/ e ~/.bash_profile. Questi files sono files di inizializzazione e vengono letti quando la shell bash viene invocata. Al momento del logout da parte dell’utente, bash legge ~/.bash_logout.
Variabili di ambiente • HOME:Il pathname della home dell’utente (l’argomento di default di cd). • PATH: Il “search path” per i comandi. É un elenco delle directories (separate da :) nelle quali la shell cerca il comando da eseguire. • Solitamente, si lancia uno script nel modo seguente: • $ ./trash.sh • Ponendo PATH=$PATH:. la nostra working directory viene inclusa nel “search path” per i comandi, e possiamo digitare semplicemente: • $ trash.sh
Variabili di ambiente • LOGNAME: contiene il nome dell’utente. • HOSTNAME: contiene il nome della macchina. • MACHTYPE: hardware del sistema. • PS1: sequenza di caratteri visualizzata davanti al prompt. • \t ora • \d data • \w current directory • \W ultima parte della current directory • \u nome dell’utente • \$ carattere del prompt Esempio [lferrari@homelinux lferrari]$ PS1=‘ciao \u *’ ciao lferrari* _ • UID: contiene l’id number dell’utente (non può essere cambiato).
Il comandoexit • Il comando exit può essere usato per terminare uno script. Esso restituisce un valore, che è disponibile per il processo padre dello script. • Quando uno script termina col comando exitsenza ulteriori parametri, lo stato di uscita è lo stato di uscita dell’ultimo comando eseguito nello script. #!/bin/bash COMMAND_1 . . . # exit with status of last command. COMMAND_LAST exit #!/bin/bash COMMAND_1 . . . # exit with status of last command. COMMAND_LAST exit $?
Il comando exit • Il comando exit può essere usato per terminare uno script. Esso restituisce un valore, che è disponibile per il processo padre dello script. • Quando uno script termina con exit nnn dove nnn=0-255, lo stato di uscita è nnn.
Il Comando read • Il comando readconsente di leggere l’input da tastiera e memorizzarlo in una variabile. • Esempio (read.sh) • #!/bin/bash echo -n “Enter name of file to delete: ” read file echo “Type 'y' to remove it, 'n' to change your mind ... ” rm -i $file echo "That was YOUR decision!" • La linea 3 crea una variabile chiamata file e le assegna l’input da tastiera. Quindi il valore di questa variabile viene richiamato inserendo il simbolo ‘$’ davanti ad essa.
Il Comando read • Opzioni • read –s (non stampa a video l’input) • read –nN (accetta soltanto N caratteri di input) • read –p “message” (visualizza il messaggio “message”) • read –tT (accetta l’input per T secondi) • Esempio $ read –s –n1 -p “Yes (Y) or not (N)?” answer Yes (Y) or not (N) ? (digitare Y: non si vedrà) $ echo $answer Y
Sostituzione dei comandi • La “virgoletta retrograda”, o accento grave, “`” è diversa dalla virgoletta “´”. Essa viene usata per la sostituzione dei comandi: `command` • $ LIST=`ls` $ echo $LIST hello.sh read.sh • PS1=“`pwd`>” /home/rinaldi/didattica/> • Possiamo eseguire la sostituzione dei comandi anche usando $(command) • $ LIST=$(ls) $ echo $LIST hello.sh read.sh • rm $( find / -name “*.tmp” ) • ls $( pwd ) • ls $( echo /bin )
Esempio $ a=`echo Hello` $ echo $a $ echo ‘$a’ $ b=`ls /home` $ echo $b $ echo $a $b $ echo “$a $b”
Operatori aritmetici + somma - sottrazione * moltiplicazione / divisione ** esponenziazione % modulo Esempio $ a=/(5+2/)*3 $ echo $a $ b=2**3 $ echo $a+$b
Valutazioni aritmetiche • Il costrutto let può essere usato per creare funzioni matematiche • $ let X=10+2*7 $ echo $X 24 $ let Y=X+2*4 $ echo $Y 32 • Un’espressione aritmetica può essere valutata usando $[expression] o $((expression)) • $ echo $((123+20)) 143 • $ VALORE=$[123+20] • $ echo $[10*$VALORE] 1430 • $ echo $[2**3] • $ echo $[8%3] Non è necessario usare $X per riferirsi al valore di X
Valutazioni aritmetiche • Esempio (operations.sh) • #!/bin/bashecho -n “Enter the first number: ”; read x echo -n “Enter the second number: ”; read y add=$(($x + $y)) sub=$(($x - $y)) mul=$(($x * $y)) div=$(($x / $y)) mod=$(($x % $y)) # print out the answers:echo “Sum: $add”echo “Difference: $sub”echo “Product: $mul” echo “Quotient: $div”echo “Remainder: $mod”
Costrutti condizionali • Le strutture condizionali ci permettono di decidere se eseguire un’azione oppure no, a seconda del valore di un’espressione da valutare. Il costrutto condizionale fondamentale è: • if [ expression ]; then statements elif [ expression ]; then statements else statements fi • Le parti elif (else if) e else sono opzionali.
Espressioni • Un’espressione può essere: un confronto fra stringhe, un confronto fra numeri, un operatore su file, un operatore logico ed è rappresentata da [ expression ]: • Confronto fra stringhe: • = per valutare se due stringhe sono uguali • != per valutare se due stringhe sono diverse • -n per valutare se la lunghezza di una stringa è maggiore di zero • -z per valutare se la lunghezza di una stringa è uguale a zero • Esempi: • [ s1 = s2 ] (vero se s1 è uguale a s2, altrimenti falso) • [ s1 != s2 ] (vero se s1 è diverso da s2, altrimenti falso) • [ s1 ] (vero se s1 è non vuota, altrimenti falso) • [ -n s1 ] (vero se s1 ha lunghezza maggiore di 0, altrimenti falso) • [ -z s2 ] (vero se s2 ha lunghezza 0, altrimenti falso)
Espressioni • Confronto fra numeri: • -eq valuta se due numeri sono uguali • -ge valuta se un numero è maggiore o uguale a un altro • -le valuta se un numero è minore o uguale a un altro • -ne valuta se due numeri sono diversi • -gt valuta se un numero è maggiore di un altro • -lt valuta se un numero è minore di un altro • Esempi: • [ n1 -eq n2 ] (vero se n1 è uguale a n2, altrimenti falso) • [ n1 -ge n2 ] (vero se n1 è maggiore o uguale a n2, altrimenti falso) • [ n1 -le n2 ] (vero se n1 è minore o uguale a n2, altrimenti falso) • [ n1 -ne n2 ] (vero se n1 è diverso da n2, altrimenti falso) • [ n1 -gt n2 ] (vero se n1 è maggiore di n2, altrimenti falso) • [ n1 -lt n2 ] (vero se n1 è minore di n2, altrimenti falso)
#!/bin/bash # if0.sh echo -n “Enter your login name: " read name if [ “$name” = “$LOGNAME” ]; then echo “Hello, $name. How are you today ?” else echo “You are not $LOGNAME, so who are you ?” fi • #!/bin/bash # if1.sh echo -n “Enter a number 1 < x < 10: " read num if [ “$num” -lt 10 ]; then if [ “$num” -gt 1 ]; then echo “$num*$num=$(($num*$num))” else echo “Wrong insertion !” fi else echo “Wrong insertion !” fi
Espressioni • Operatori su files: • -d controlla se il cammino dato rappresenta una directory • -f controlla se il cammino dato rappresenta un file ordinario • -e controlla se il nome del file esiste • -s controlla se un file ha lunghezza maggiore di 0 • -r controlla se si possiede il permesso di lettura per un file o una directory • -w controlla se si possiede il permesso di scrittura per un file o una directory • -x controlla se si possiede il permesso di esecuzione per un file o una directory • Esempi: • [ -d fname ] (vero se fname è una directory, altrimenti falso) • [ -f fname ] (vero se fname è un file ordinario, altrimenti falso) • [ -e fname ] (vero se fname esiste, altrimenti falso) • [ -s fname ] (vero se la lunghezza di fname è maggiore di 0, altrimenti falso) • [ -r fname ] (vero se fname ha il permesso di lettura, altrimenti falso) • [ -w fname ] (vero se fname ha il permesso di scrittura, altrimenti falso) • [ -x fname ] (vero se fname ha il permesso di esecuzione, altrimenti falso)
Esempio • #!/bin/bashif [ -f /etc/fstab ]; then cp /etc/fstab . echo “Done.” else echo “This file does not exist.” exit 1 fi • Esercizio. Scrivere uno script di shell che prenda in input un nome di file <pippo>: • Lo script controlla se esiste una cartella Backup, altrimenti la crea. • Se il file cercato esiste, copia il file con lo stesso nome + .bak nella cartella Backup. • Se il file non esiste, allora visualizza il messaggio “The file <pippo> does not exist!!!”
Soluzione #!/bin/bash if [ ! –d ./Backup ] then mkdir ./Backup fi read –p “insert the name of a file” pippo if [ -f $pippo ] then cp $pippo ./Backup/$pippo.bak else echo “The file $pippo does not exist!!!” fi
Espressioni • Operatori logici: • ! negare (NOT) un’espressione logica • -a congiunzione (AND) tra due espressioni logiche • -o disgiunzione (OR) tra due espressioni logiche • #!/bin/bash # if3.sh echo -n “Enter a number 1 < x < 10:” read num if [ “$num” -gt 1 –a “$num” -lt 10 ]; then echo “$num*$num=$(($num*$num))” else echo “Wrong insertion !” fi
Espressioni • Operatori logici: • && congiunzione (AND) tra due espressioni logiche • || disgiunzione (OR) tra due espressioni logiche • #!/bin/bash # if4.sh echo -n "Enter a number 1 < x < 10: " read num if [ “$number” -gt 1 ] && [ “$number” -lt 10 ]; then echo “$num*$num=$(($num*$num))” else echo “Wrong insertion !” fi
Esempio • $ cat iftrue.sh # iftrue.sh #!/bin/bash echo “Enter a path: ”; read x ifcd $x 2> /dev/null then echo “I am in $x and it contains”; ls else echo “The directory $x does not exist”; exit 1 fi • $ ./iftrue.sh Enter a path: /home srinaldi afrosini riccardo … • $ ./iftrue.sh Enter a path: pippo The directory pippo does not exist
Parametri di shell • Un parametro posizionale corrisponde ad un argomento fornito alla shell al momento dell’esecuzione di un programma. Il primo argomento specificato corrisponde alla variabile 1, il secondo argomento alla variabile 2 e così via. Il parametro posizionale “N” può essere referenziato come “${N}”, o come “$N” quando “N” consiste in una singola cifra. • Parametri speciali • $# è il numero dei parametri passati • $0 rende il nome dello script di shell in esecuzione nonchè la sua posizione nel file system • $* rende una singola parola contenente tutti i parametri passati allo script • $@ rende un array di parole contenente tutti i parametri passati allo script • $ cat sparameters.sh ( sparameters.sh ) #!/bin/bash echo “$#; $0; $1; $2; $*; $@” $ sparameters.sh alba chiara 2; ./sparameters.sh; alba; chiara; alba chiara; alba chiara
Trash • $ cat trash.sh ( trash.sh ) #!/bin/bash if [ $# -eq 1 ]; then if [ ! –d “$HOME/trash” ]; then mkdir “$HOME/trash” fi mv $1 “$HOME/trash” else echo “Use: $0 filename” exit 1 fi
Il costrutto case • Viene usato per eseguire azioni basate su valori specifici. Usato spesso al posto di un costrutto if se c’è un numero elevato di condizioni. • Il valore usato può essere un’espressione. • Ciascun insieme di azioni deve concludersi con una coppia di punto e virgola. • Il simbolo *) viene usato per accettare ogni valore non corrispondente con la lista dei valori. • case $var in val1) statements;; val2) statements;; *) statements;; esac
Esempio • #!/bin/bash ( case.sh ) echo -n “Enter a number 1 < x < 10: ” read x case $x in 2) echo “Value of x is 2.”;; 3) echo “Value of x is 3.”;; 4) echo “Value of x is 4.”;; 5) echo “Value of x is 5.”;; 6) echo “Value of x is 6.”;; 7) echo “Value of x is 7.”;; 8) echo “Value of x is 8.”;; 9) echo “Value of x is 9.”;; 1 | 10) echo “wrong number.”;; *) echo “Unrecognized value.”;; esac
Costrutti di iterazione • Il ciclo for viene usato quando si vuole ripetere un blocco di comandi in corrispondenza di valori tratti da un elenco. • forvar in list do istruzioni done • Le istruzioni vengono eseguite assegnando avarciascun valore inlist. • #!/bin/bash let sum=0 for num in 1 2 3 4 5 do let sum=$sum+$num done echo $sum
Costrutti di iterazione: <list> • #!/bin/bashfor x in paper pencil pen; do echo “The value of variable x is: $x” sleep 1 done #The value of variable x is paper # The value of variable x is pencil # The value of variable x is pen • #!/bin/bashfor x in “paper A4” “pencil STADTLER” “pen BIC”; do echo “The value of variable x is: $x” sleep 1 done #The value of variable x is paper A4 # The value of variable x is pencil STADTLER # The value of variable x is pen BIC
Costrutti di iterazione: <list> • #!/bin/bashlista=“antonio michele paolo luca” for x in $lista do echo “The value of variable x is: $x” sleep 1 done #The value of variable x is antonio # The value of variable x is michele # The value of variable x is paolo # The value of variable x is luca
Costrutti di iterazione: <list> • #!/bin/bash for x in * do ls -l “$x” sleep 1 done #Lists all files in current directory • #!/bin/bash for x in /bin do ls -l “$x” done #Lists all files in /bin
Costrutti di iterazione: <list> #!/bin/bash read –p “Insert the name of a directory” directory echo "symbolic links in directory \” $directory \” " for file in $( find $directory -type l ) # -type l = symbolic links do echo "$file" done | sort # Otherwise file list is unsorted
Costrutti di iterazione: <list> • Se la partelistviene omessa, avar viene assegnato ciascun parametro passato allo script ( $1, $2, $3,…).
Costrutti di iterazione: <list> • Se la partelistviene omessa, avar viene assegnato ciascun parametro passato allo script ( $1, $2, $3,…). • $ cat for1.sh ( for1.sh ) #!/bin/bashfor x do echo “The value of variable x is: $x” sleep 1 done $ for1.sh alba chiara The value of variable x is: alba The value of variable x is: chiara
Esempio 1 #!/bin/bash ( old.sh ) # Move the command line arg files to old directory. if [ $# -eq 0 ] #check for command line arguments then echo “Usage: $0 file …” exit 1 fi if [ ! –d “$HOME/old” ] then mkdir “$HOME/old” fi echo The following files will be saved in the old directory: echo $* for p in $* #loop through all command line arguments do mv $p “$HOME/old/” chmod 400 “$HOME/old/$p” done ls -l “$HOME/old”
Esempio 2 #!/bin/bash ( args.sh ) # Invoke this script with several arguments: “one two three“ if [ ! -n “$1” ]; then echo “Usage: $0 arg1 arg2 ..." ; exit 1 fi echo ; index=1 ; echo “Listing args \”\$*\”:” for arg in “$*” ; do echo “Arg $index = $arg” let “index+=1” # increase variable index by one done echo “Entire arg list seen as single word.” echo ; index=1 ; echo “Listing args with \”\$@\”:” for arg in “$@” ; do echo “Arg $index = $arg” let “index+=1” done echo “Arg list seen as separate words.”
Operazioni sulle variabili …… let “index += 5”#incrementa la variabile #index di 5 …… += #incrementa la variabile -= #decrementa la variabile *= #moltiplica la variabile /= #divide la variabile
Arrays • Nella shell bash, possiamo usare gli arrays. Il modo più semplice per crearne uno è usare uno dei due metodi seguenti: • pet[0]=dog pet[1]=cat pet[2]=fish pet[4]=apple • pet=( dog cat fish apple ) • Si possono inserire fino a 1024 elementi. Per estrarre un valore, digitare${arrayname[i]}. • $ echo ${pet[0]} dog • $ echo ${pet[2]} fish
Arrays • Per estrarre tutti gli elementi, usare un asterisco come segue: echo ${arraynames[*]} • Per vedere quanti elementi ci sono nell’array: echo ${#arraynames[*]} • Si possono utilizzare gli arrays nei cicli per realizzare la lista di un ciclofor: • for x in ${arrayname[*]} do echo $x done
Un “for” alternativo • Una forma alternativa per la struttura for è • for (( EXPR1 ; EXPR2 ; EXPR3 )) do istruzioni done • Per prima cosa, viene valutata l’espressione aritmetica EXPR1. Quindi EXPR2 viene valutata ripetutamente fino a che non assume risulta falsa. Ogni volta che EXPR2 è vera, le istruzioni vengono eseguite e, in coda, viene eseguita EXPR3.