Programare în Shell - Utilizarea Sistemelor de Operarepirofti/uso/uso-curs-10.pdf · VarianteShell...

32
Programare în Shell Utilizarea Sistemelor de Operare Paul Irofti Universitatea din Bucures , ti Facultatea de Matematică s , i Informatică Department de Informatică Email: [email protected]

Transcript of Programare în Shell - Utilizarea Sistemelor de Operarepirofti/uso/uso-curs-10.pdf · VarianteShell...

Programare în ShellUtilizarea Sistemelor de Operare

Paul Irofti

Universitatea din Bucures,tiFacultatea de Matematică s, i Informatică

Department de InformaticăEmail: [email protected]

Motivat, ie

I de multe ori vrem să avem o singură comandă pentru un s, ir decomenzi

I comenzile sunt preponderent comenzi shell sau din sistem, nuoperat, ii logice sau aritmetice

I avem nevoie să scriem un program scurt rapidI vrem să funct, ioneze pe orice alt sistem pentru a repeta un set

de operat, ii de configurare sau administrareI bazat pe CS2043 Unix and Scripting de la Cornell University

(cursurile 9 s, i 10)

Variante Shell

I sh(1) – Bourne shellI printre primele shelluriI disponibilă oriunde în /bin/shI funct, ionalitate redusăI portabilitate

I csh(1) – C shell, comenzi apropiate de lucru în CI ksh(1) – Korn shell, bazat pe sh(1), succesor csh(1)I bash(1) – Bourne Again shell

I cea mai răspândităI există s, i în Windows 10I majoritatea scripturilor moderne scrise în bash(1)I acest rezultat a dus la o lipsă de portabilitateI proiect mare cu multe linii de cod s, i probleme de securitate

Variabile Shell

I două tipuri de variabile: locale s, i de mediuI variabilele locale există doar în instant,a curentă a shell-uluiI convent, ie: variabilele locale se notează cu litere miciI asignare: x=1 (fără spat, ii!)I x = 1: se interpretează drept comanda x cu argumentele = s, i 1I folosirea valorii unei variabile se foloses,te prin prefixarea

numelui cu $I cont, inutul oricărei variabile poate fi afis,at cu comanda

echo(1)

$ x=1$ echo $x1

Variabile de mediu

I folosite de sistem pentru a defini modul de funct, ionare aprogramelor

I shell-ul trimite variabilele de mediu proceselor sale copilI env(1) – afis,ează toate variabilele de mediu setateI variabile importante

I $HOME – directorul în care se t, in datele utilizatorului curentI $PATH – listă cu directoare în care se caută executabileleI $SHELL – programul de shell folosit implicitI $EDITOR – programul de editare fis, iere implicitI $LANG – limba implicită (ex. ro_RO.UTF-8)

I export(1) – se foloses,te pentru a seta o variabilă de mediuI printenv(1) – se foloses,te pentru a afis,a o variabilă de mediu

$ expo r t V=2$ p r i n t e n v V2$ echo $V2

Exemplu: Variabilă locală

$ LANG=ro_RO .UTF−8$ p r i n t e n v LANG$ echo $LANGro_RO .UTF−8$ bashbash −4.4$ p r i n t e n v LANGbash −4.4$ tbash : t : command not foundbash −4.4$ echo $LANG

bash −4.4$ e x i t

Exemplu: Variabilă de mediu

$ e xpo r t LANG=ro_RO .UTF−8$ p r i n t e n v LANGro_RO .UTF−8$ bashbash −4.4$ p r i n t e n v LANGro_RO .UTF−8bash −4.4$ echo $LANGro_RO .UTF−8bash −4.4$ tbash : t : comandă neg ă s i t ă

Variable expansion

Variabilele pot fi mai mult decât simplii scalariI $(cmd) – evaluează întâi comanda cmd, iar rezultatul devine

valoarea variabilei

$ echo $ (pwd)/home/ pau l$ x=$ ( f i n d . −name \∗ . c )$ echo $x. / b a t l e f t . c . / p c i e . c . / maxint . c . / e i s a i d . c

I $((expr)) – evaluează întâi expresia aritmetică, iar rezultatuldevine valoarea variabilei

$ x=1$ echo $ ((1+1))2$ echo $ ( ( x+1))2$ echo $ ( ( x<1))0

$ echo $ ( ( x++))1$ echo $ ( ( x++))2$ echo $((++x ) )4

Quoting

S, irurile de caractere sunt interpretate diferit în funct, ie de citare:I Single quotes ”

I toate caracterele îs, i păstrează valoareaI caracterul ’ nu poate apărea în s, ir, nici precedat de "\"I exemplu:

$ echo ’Am v a r i a b i l a $x ’Am v a r i a b i l a $x

I Double quotes ""I caractere speciale $ ‘ \ (opt, ional !)I restul caracterelor îs, i păstrează valoareaI exemplu:

$ echo "$USER has home i n $HOME"pau l has home i n /home/ pau l

I Back quotes “ – funct, ionează ca $()

$ echo "Today i s ‘ date ‘ "Today i s Wed May 2 18 : 00 : 08 EEST 2018

Înlănt,uirea comenzilor

I cmd1; cmd2 – înlănt,uire secvent, ială, cmd2 imediat după cmd1I cmd1 | filtru | cmd2 – ies, irea comenzii din stânga este

intrarea celei din dreapta operatorului |I cmd1 && cmd2 – execută a doua comandă doar dacă prima s-a

executat cu succesI cmd1 || cmd2 – execută a doua comandă doar dacă prima a

es,uatI exemplu:

$ mkdir a c t e && mv ∗ . docx ac t e /$ l s −lR | t e e f i l e s . l s t | wc − l$ s sh example . org | | echo " Connect ion f a i l e d !"

Scripting

DefinitionScript-urile sunt programe scrise pentru un mediu run-time specificcare automatizează execut, ia comenzilor ce ar putea fi executatealternativ manual de către un operator uman.

I nu necesită compilareI execut, ia se face direct din codul sursăI de acea programele ce execută scriptul se numesc

interpretatoare înloc de compilatoareI comenzile executate se mai numesc s, i byte-codeI astăzi granit,a dintre compilatoare s, i interpretatoare nu mai

este atât de clară (JIT, tiered compilation)I exemple: perl, ruby, python, sed, awk, ksh, csh, bash

Shebang (#!)

I reprezintă prima linie din orice script UnixI are forma #!/path/to/interpreterI exemple: #!/bin/sh, #!/usr/bin/pythonI pentru protabilitate folosit, i env(1) pentru a găsi unde este

instalat interpretatorulI exemple: #!/usr/bin/env ruby, #!/usr/bin/env perlI oriunde altundeva în script # este interpretat ca început de

comentariu s, i restul linei este ignorată (echivalent // în C)I introdusă de Denis Ritchie circa 1979

Exemplu: hello.sh

1. Scriem fis, ierul hello.sh cu comenzile dorite

#!/ b i n / sh

# Sa l u t e the u s e recho "He l l o , $USER!"

2. Permitem execut, ia: chmod +x hello.sh

3. Executăm:

$ . / h e l l o . shHe l l o , pau l !

Variabile speciale în scripturi

I $1, $2, ..., ${10}, ${11}, ... – argumentele în ordinea primităI dacă numărul argumentului are mai mult de două cifre, trebuie

pus între acoladeI $0 – numele scriptului (ex. hello.sh)I $# – numărul de argumente primiteI $* – toate argumentele scrise ca "$1 $2 ... $n"I $@ – toate argumentele scrise ca "$1" "$2" ... "$n"I $? – valoarea ies, irii ultimei comenzi executateI $$ – ID-ul procesului curentI $! – ID-ul ultimului proces suspendat din execut, ie

Exemple: argumente script

I add.sh – adună două numere

#!/ b i n / shecho $ ( ( $1 + $2 ) )

apel:

$ sh add . sh 1 23

I tolower.sh – imită funct, ia din C tolower(3)

#!/ b in / sht r ’ [A−Z ] ’ ’ [ a−z ] ’ < $1 > $2

apel:

$ echo "WHERE ARE YOU?" > sc reaming . t x t$ . / t o l owe r . sh sc r eaming . t x t decent . t x t$ ca t decent . t x twhere a r e you ?

Blocuri de control

Pentru scripturi mai complexe avem nevoie, ca în orice limbaj, deblocuri de control

I condit, ionale – if, test [ ], caseI iterative – for, while, untilI comparative – -ne, -lt, -gtI funct, ii – functionI ies, iri – break, continue, return, exit

If

I cuvinte cheie: if, then, elif, else, fiI exemplu ce foloses,te toate cuvintele cheie:

i f cmd1then

cmd2cmd3

e l i f cmd4then

cmd5cmd6

e l s ecmd7

f i

I o condit, ie este adevărată dacă comanda asociată esteexecutată cu succes ($?=0)

Exemplu: if

Caută în fis, ier date s, i le adaugă dacă nu le găses,te

#!/ b in / shi f g rep "$1" $2 > /dev/ n u l lthen

echo "$1 found i n f i l e $2"e l s e

echo "$1 not found i n f i l e $2 , append ing "echo "$1" >> $2

f i

apel:

$ . / t e x t . sh who decent . t x twho not found i n f i l e decent . t x t , append ing$ ca t decent . t x twhere a r e you?who

test sau [ ]

I nu dorim să testăm tot timpul execut, ia unei comenziI există expresii pentru a compara sau verifica variabileI test expr – evaluează valoarea de adevăr a lui exprI [ expr ] – efectuează aceias, i operat, ie (atent, ie la spat, ii!)I expresiile pot fi legate logic prin

I [ expr1 -a expr2 ] – s, iI [ expr1 -o expr2 ] – sauI [ ! expr ] – negat, ie

Expresii test: numere

I [ n1 -eq n2 ] – n1 = n2

I [ n1 -ne n2 ] – n1 6= n2

I [ n1 -ge n2 ] – n1 ≥ n2

I [ n1 -gt n2 ] – n1 > n2

I [ n1 -le n2 ] – n1 ≤ n2

I [ n1 -lt n2 ] – n1 < n2

Expresii test: s, iruri de caractere

I [ str ] – str are lungime diferită de 0I [ -n str ] – str nu e golI [ -z str ] – str e gol ("")I [ str1 = str2 ] – stringuri identiceI [ str1 == str2 ] – stringuri identiceI [ str1 != str2 ] – stringuri diferite

Expresii test: fis, iere

I -e path – verifică dacă există calea pathI -f path – verifică dacă path este un fis, ierI -d path – verifică dacă path este un directorI -r path – verifică dacă avet, i permisiunea de a citi pathI -w path – verifică dacă avet, i permisiunea de a scrie pathI -x path – verifică dacă avet, i permisiunea de a executa path

while

I execută blocul cât timp comanda cmd se execută cu succes

wh i l e cmddo

cmd1cmd2

done

I în loc de comandă putem avea o expresie de testI într-o singură linie: while cmd; do cmd1 cmd2; done

Exemplu: while

Afis,ează toate numerele de la 1 la 10:

i=1wh i l e [ $ i − l e 10 ]do

echo " $ i "i=$ ( ( $ i +1))

done

Sau într-o singură linie:i=1; while [ $i -le 10 ]; do echo "$i"; i=$(($i+1));done

until

I execută blocul cât timp comanda cmd se execută fără succes

u n t i l cmddo

cmd1cmd2

done

I în loc de comandă putem avea o expresie de testI într-o singură linie: until cmd; do cmd1 cmd2; done

for

I execută blocul pentru fiecare valoare din listă

f o r va r i n s t r 1 s t r 2 . . . s t rNdo

cmd1cmd2

done

I var ia pe rând valoarea str1, pe urmă str2 până la strNI de regulă comenzile din bloc (cmd1, cmd2) sunt legate de varI comanda for are mai multe forme, aceasta este cea mai

întâlnităI într-o singură linie:

for var in str1 str2 ... strN; do cmd1 cmd2; done

Exemplu: for

Compileză toate fis, ierele C din directorul curent

f o r f i n ∗ . cdo

echo " $ f "cc $ f −o $ f . out

done

Sau într-o singură linie:for f in *.c; do echo "$f"; cc $f -o $f.out; done

for tradit, ional

I formă întâlnite doar în unele shell-uri, nu este portabilI execută blocul urmând o sintaxă similară C

f o r ( ( i =1; i <=10; i++ ) )do

echo $ idone

I i ia pe rând toate valorile între 1 s, i 10I în exemplu, blocul afis,ează $i, dar pot apărea oricâte alte

comenziI într-o singură linie:

for (( i=1; i<=10; i++ )); do cmd1 cmd2; done

Case

I se comportă similar cu switch în C

ca se va r i np a t t e r n 1 )

cmd1cmd2; ;

p a t t e r n 2 )cmd3; ;

∗ )de fau l t cmd; ;

e sac

I pattern – poate fi un string sau orice expresie de shell (similarcu wildcards-urile folosite pentru grep(1))

Exemplu: case

Parsare subcomandă pentru un program SQL:

ca se "$1" i n’CREATE’ )

do_creat; ;

’ INSERT ’ )do_ in s e r t; ;

’SELECT ’ )do_se l e c t; ;

’USE ’ )do_use; ;

’DROP’ )do_drop; ;

∗)p r i n t_usage

e sac

read

I cites,te una sau mai multe variabile din stdinI sintaxă: read var1 var2 ... varN

$ read x y1 2$ echo $x $y1 2

I dacă nu este dată nici o variabilă, se as,teaptă să fie unasingură s, i pune rezultatul în $REPLY

$ readh e l l o$ echo $REPLYh e l l o

I citire line cu linie dintr-un fis, ier:cat foo.txt | while read LINE; do echo $LINE done

Depanare

Pentru a depana un script apelat, i-l cu shell-ul folosit s, i opt, iunea -x.Comenzile executate apar pe ecran prefixate cu + .

$ sh −x t o l owe r . sh sc r eaming . t x t decent . t x t+ t r [A−Z ] [ a−z ]+ < sc reaming . t x t+ > decent . t x t