Fundamentele scriptului Bash

Shell script-urile sunt utilizate pe scară largă în lumea UNIX. Sunt excelente pentru accelerarea sarcinilor repetitive și simplificarea logicii complexe de execuție. Ele pot fi la fel de simple ca un set de comenzi sau pot orchestra sarcini complexe. În acest tutorial, vom afla mai multe despre limbajul de scripting Bash scriind un exemplu de script pas-cu-pas.


Problema Fizz-Buzz

Una dintre cele mai bune modalități de a învăța despre o nouă limbă este de exemplu. Să începem cu una.

Problema Fizz-Buzz este una foarte simplă. A devenit faimos după ce un programator, pe nume Imran, a folosit-o ca test de interviu. Se pare că 90-99,5% dintre candidații la un post de programare nu pot scrie singur cel mai simplu program. Imran a luat acest simplu joc Fizz-Buzz și ia cerut candidații să o rezolve. Mulți au urmat exemplul lui Imran și, astăzi, este una dintre cele mai solicitate întrebări frecvente pentru un program de programare. Dacă angajați și aveți nevoie de o modalitate de a filtra peste 90% dintre candidați, este o problemă importantă de prezentat.

Iată regulile:

  • Luați și imprimați numerele între 1 și 100.
  • Când un număr este divizibil cu 3, imprimați "Fizz" în loc de număr.
  • Când este divizibil cu 5, scrieți în loc "Buzz".
  • Când este divizibil atât cu 3 cât și cu 5, imprimați "FizzBuzz".

Cam despre asta e. Sunt sigur că majoritatea dintre voi puteți vizualiza deja cele două sau trei dacă declarații pentru a rezolva acest lucru. Să lucrăm prin aceasta folosind limbajul de scripting Bash.


shebang

Un shebang se referă la combinația dintre caracterele hash și exclamation mark: #!. Încărcătorul de programe va căuta un shebang pe prima linie a scriptului și va folosi interpretul specificat în el. Un shebang constă din următoarea sintaxă: #!interpret [parametri]. Interpretul este programul folosit pentru interpretarea limbii noastre. Pentru scripting-ul bash, asta ar fi / Bin / bash. De exemplu, dacă doriți să creați un script în PHP și să îl rulați în consola, probabil că doriți să îl utilizați / Usr / bin / php (sau calea către executabilul PHP pe mașina dvs.) ca interpret.

#! / Usr / bin / php  

Da, asta va funcționa! Nu este simplu? Doar asigurați-vă că faceți fișierul executabil mai întâi. Odată ce faceți, acest script va afișa informațiile dvs. PHP așa cum v-ați aștepta.

Bacsis: Pentru a vă asigura că scriptul dvs. va funcționa pe cât mai multe sisteme posibil, puteți utiliza / Bin / env în shebang. Ca atare, în loc de / Bin / bash, ai putea folosi / bin / env bash, care va funcționa pe sisteme în care executabilul bash nu se află înăuntru /cos.


Rezultatul textului

Ieșirea unui script va fi egală cu, după cum s-ar putea aștepta, tot ce este afișat din comanda. Cu toate acestea, dacă vrem în mod explicit să scriem ceva pe ecran, putem folosi ecou.

#! / bin / bash ecou "Hello World"

Rularea acestui script va imprima "Hello World" în consola.

csaba @ csaba ~ $ ./helloWorld.sh Buna ziua csaba @ csaba ~ $

Introducerea variabilelor

Ca și în cazul oricărui limbaj de programare, când scrieți scripturile shell, puteți utiliza variabilele.

#! / bin / bash message = mesajul "Hello World" echo $

Acest cod produce exact același mesaj "Hello World". După cum puteți vedea, pentru a atribui o valoare unei variabile, scrieți doar numele - excludeți semnul dolarului în fața acesteia. De asemenea, aveți grijă cu spațiile; nu pot exista spații între numele variabilei și semnul egal. Asa de Mesajul = „Bună ziua“ in loc de mesaj = 'Hello'

Când doriți să utilizați o variabilă, puteți lua valoarea din ea la fel cum am făcut în ecou comanda. Prependând a $ la numele variabilei va returna valoarea sa.

Bacsis: În ecranul bash nu sunt necesare punctajele punctuale. Puteți să le folosiți în majoritatea cazurilor, dar aveți grijă: pot avea un înțeles diferit de ceea ce vă așteptați.


Imprimarea numerelor între 1 și 100

Continuând cu demo-ul nostru, trebuie să trecem prin toate numerele între 1 și 100. Pentru aceasta, va trebui să folosim un pentru buclă.

#! / bin / bash pentru numărul în 1 ... 100; se face echo $ numărul făcut

Există mai multe lucruri noi care merită notate în acest exemplu - care, apropo, imprimă toate numerele de la 1 la 100, câte un număr simultan.

  • pentru sintaxa în Bash este: pentru VARIABLE in RANGE; face COMMAND făcut.
  • Bretelele se vor transforma 1 ... 100 într-o gamă în exemplul nostru. Ele sunt folosite și în alte contexte, pe care le vom examina în scurt timp.
  • do și pentru sunt de fapt două comenzi separate. Dacă doriți să plasați două comenzi pe o singură linie, va trebui să le separați cumva. O modalitate este de a utiliza punct și virgulă. Alternativ, ați putea scrie codul fără punct și virgulă prin deplasare do la următoarea linie.
#! / bin / bash pentru numărul din 1 ... 100 nu efectuați echo $ numărul

Prima decizie

Acum că știm cum să tipărim toate numerele între 1 și 100, este timpul să luăm prima noastră decizie.

#! / bin / bash pentru numărul în 1 ... 100; dacă [$ ((număr% 3)) -eq 0]; apoi echo "Fizz" altceva echo $ numărul fi făcut

Acest exemplu va scoate "Fizz" pentru numere divizibile prin 3. Din nou, trebuie să ne ocupăm de o sintaxă nouă. Să le luăm unul câte unul.

  • dacă ... atunci ... altceva ... fi - aceasta este sintaxa clasică pentru o dacă declarație în Bash. Desigur, altfel parte este opțională - dar este necesară pentru logica noastră în acest caz.
  • dacă valoarea COMMAND-RETURN-VALUE; atunci… - dacă va executa dacă valoarea de retur a comenzii este zero. Da, logica în Bash este bazată pe zero, ceea ce înseamnă că comenzile care execută ieșirea cu succes cu un cod de 0. Dacă ceva nu merge bine, pe de altă parte, un întreg pozitiv va fi returnat. Pentru a simplifica lucrurile: se ia în considerare orice altceva decât 0 fals.
  • Expresiile matematice din Bash sunt specificate prin paranteze duble. $ ((Număr% 3)) va returna valoarea rămasă de împărțire a variabilei, număr, de 3. Vă rugăm să rețineți că nu am folosit $ în interiorul parantezei - numai în fața lor.

S-ar putea să te întrebi unde este comanda în exemplul nostru. Nu este doar o coadă cu o expresie ciudată în ea? Ei bine, se pare asta [ este de fapt o comandă executabilă. Pentru a juca cu asta, încercați următoarele comenzi în consola dumneavoastră.

csaba @ csaba ~ $ care [/ usr / bin / csaba @ csaba ~ $ [0 -eq 1] csaba @ csaba ~ $ echo $? 1 csaba @ csaba ~ $ [0 -eq 0] csaba @ csaba ~ $ echo $? 0

Bacsis: Valoarea de ieșire a unei comenzi este întotdeauna returnată în variabilă, ? (semnul întrebării). Acesta este suprascris după executarea fiecărei noi comenzi.


Verificați pentru Buzz

Mergem bine până acum. Avem "Fizz"; acum să facem partea "Buzz".

#! / bin / bash pentru numărul în 1 ... 100; dacă [$ ((număr% 3)) -eq 0]; apoi echo "Fizz" elif [$ ((număr% 5)) -eq 0]; apoi echo "Buzz" altceva echo $ numărul fi făcut

Mai sus, am introdus o altă condiție pentru divizibilitate cu 5: Elif afirmație. Acest lucru, desigur, se traduce la altfel dacă, și va fi executat dacă se întoarce comanda care o urmează Adevărat (sau 0). După cum puteți observa, afirmațiile condiționale din interiorul [] sunt de obicei evaluate cu ajutorul unor parametri, cum ar fi -eq, care înseamnă "egal".

Pentru sintaxa, arg1 OP arg2, OP este unul din -eq, -ne, -lt, -Le, -gt, sau -GE. Acești operatori binari aritmetici se întorc Adevărat dacă ARG1 este egal cu, nu egal cu, mai mic, mai mic sau egal cu, mai mare sau mai mare sau egal cu arg2, respectiv.ARG1 și arg2 pot fi numere întregi pozitive sau negative. - Bash Manual

Când încercați să comparați șiruri de caractere, puteți utiliza cele cunoscute == semn, sau chiar un singur semn egal va face. != se intoarce Adevărat când șirurile sunt diferite.


Dar Codul nu este destul de corect

Până în prezent, codul rulează, dar logica nu este corectă. Când numărul este divizibil de ambele 3 și 5, logica noastră va econa doar "Fizz". Să modificăm codul nostru pentru a satisface ultima cerință a FizzBuzz.

#! / bin / bash pentru numărul în 1 ... 100; dacă [$ ((număr% 3)) -eq 0]; apoi output = "Fizz" fi dacă [$ ((număr% 5)) -eq 0]; apoi output = "$ output Buzz" fi dacă [-z $ output]; apoi echo $ un număr altceva echo $ output; fi făcut

Din nou, a trebuit să facem o serie de schimbări. Cel mai notabil este introducerea unei variabile și apoi concatenarea lui "Buzz", dacă este necesar. Strings in bash sunt de obicei definite intre ghilimele duble (") .Cotatiile simple sunt de asemenea folosite, dar pentru o concatenare mai usoara, dublele sunt cea mai buna alegere. un text $ variabilă alt text" voi inlocui $ variabila cu conținutul său. Când doriți să concatenați variabilele cu șiruri de caractere fără spații între ele, puteți prefera să puneți numele variabilei în coarde curbate. În cele mai multe cazuri, cum ar fi PHP, nu sunteți obligat să faceți acest lucru, dar ajută foarte mult la citirea codului.

Bacsis: Nu puteți compara corzile goale. Acest lucru va returna un parametru lipsă.

Deoarece argumentele din interior [] sunt tratate ca parametri, pentru "[", acestea trebuie să fie diferite de un șir gol. Deci, această expresie, chiar dacă este logică, va produce o eroare: [$ output! = ""]. De aceea am folosit-o [-z $ ieșire], care se întoarce Adevărat dacă șirul are o lungime de zero.


Metoda de extragere pentru expresia logică

O modalitate de a ne îmbunătăți exemplul este să extragem în funcții expresia matematică din dacă declarații, cum ar fi:

Funcția #! / bin / bash esteDivisibleBy retur $ (($ 1% $ 2)) pentru numărul în 1 ... 100; dacă este isDivisibleBy $ numărul 3; apoi output = "Fizz" fi dacă esteDivisibleBy $ numărul 5; apoi output = "$ output Buzz" fi dacă [-z $ output]; apoi echo $ un număr altceva echo $ output; fi făcut

Am luat expresiile comparând restul cu zero și le-am transferat într-o funcție. Mai mult, am eliminat comparația cu zero, deoarece zero înseamnă adevărat pentru noi. Trebuie doar să întoarcem valoarea din expresia matematică - foarte simplă!

Bacsis: Definirea unei funcții trebuie să fie precedată de apelul acesteia.

În Bash, puteți defini o metodă ca funcția func_name comenzi; . Opțional, există oa doua sintaxă pentru declararea funcțiilor: func_name () comenzi; . Deci, putem lăsa șirul, funcţie si adauga "()" după numele său. Eu personal prefer această opțiune, așa cum este exemplificat în exemplul de mai sus. Este mai explicit și seamănă cu limbile de programare tradiționale.

Nu este necesar să specificați parametrii pentru o funcție în Bash. Trimiterea parametrilor către o funcție este realizată prin simpla enumerare a acestora după ce apelul funcției este separat de spații albe. Nu introduceți virgule sau paranteze în apelul funcției - nu va funcționa.

Parametrii primiți sunt atribuiți automat variabilelor după număr. Primul parametru merge la $ de 1, al doilea la $ cu 2, si asa mai departe. Variabila specială, $ cu 0 se referă numele fișierului curent al scriptului.

Să jucăm cu parametrii

#! / bin / funcția bash exampleFunc echo $ 1 echo $ 0 IFS = "X" echo "$ @" echo "$ *" exampleFunc "

Acest cod va produce următoarea ieșire:

csaba @ csaba ~ $ ./parametersExamples.sh o ./parametersExamples.sh o două două unuTwtwoXthre

Să analizăm sursa, linie cu linie.

  • Ultima linie este apelul funcției. O numim cu trei parametri de șir.
  • Prima linie după shebang este definiția funcției.
  • Prima linie din funcție scoate primul parametru: "una". Până atât de simplu.
  • A doua linie afișează numele fișierului curent al scriptului. Din nou, foarte simplu.
  • A treia linie modifică separatorul de caractere implicit la litera "X". În mod implicit, acesta este "" (un spațiu). Așa Bash știe cum sunt separați parametrii.
  • Cea de-a patra linie conține o variabilă specială, $ @. Acesta reprezintă toți parametrii ca un singur cuvânt, exact așa cum este specificat în apelul pentru funcții.
  • Linia finală transmite o altă variabilă specială, $ *. Acesta reprezintă toți parametrii, luați unul câte unul și concatenat cu prima literă a variabilei IFS. De aceea rezultatul este oneXtwoXthre.

Revenirea șirurilor din funcții

După cum am observat mai devreme, funcțiile din Bash pot întoarce numai numere întregi. Ca atare, scris retur "un șir" ar fi codul nevalid. Cu toate acestea, în multe situații, aveți nevoie de mai mult de un zero sau unul. Putem să refacem exemplul nostru FizzBuzz astfel încât, în pentru declarație, vom face doar un apel de funcție.

Funcția #! / bin / bash esteDivisibleBy return $ (($ 1% $ 2)) funcția fizzOrBuzz ifDivisibleBy $ 1 3; apoi output = "Fizz" fi dacă isDivisibleBy $ 1 5; apoi output = "$ output Buzz" fi dacă [-z $ output]; apoi echo $ 1 altceva echo $ output; fi pentru numărul din 1 ... 100; face fizzOrBuzz numărul de $ făcut

Ei bine, acesta este primul pas. Tocmai am extras tot codul într-o funcție numită fizzOrBuzz, și apoi înlocuit număr $ cu $ de 1. Cu toate acestea, toate ieșirile apar în fizzOrBuzz funcţie. Vrem să ieșim din pentru buclă cu un ecou , astfel încât să putem prefixa fiecare linie cu un alt șir. Trebuie să capturăm fizzOrBuzz funcția de ieșire.

# [...] pentru numărul din 1 ... 100; do echo "-'fizzOrBuzz $ number '" fizzBuzzer = $ (fizzOrBuzz $ number) echo "- $ fizzBuzzer" terminat

Ne-am actualizat pentru bucla doar un pic (nu alte modificări). Acum am reluat totul de două ori în două moduri diferite pentru a exemplifica diferențele dintre cele două soluții la aceeași problemă.

Prima soluție pentru captarea ieșirii unei funcții sau a altei comenzi este folosirea spintecilor. În 99% din cazuri, acest lucru va funcționa foarte bine. Puteți să vă referiți pur și simplu la o variabilă în spate după nume, așa cum am făcut-o număr $. Primele câteva linii ale producției ar trebui să pară acum:

csaba @ csaba ~ / Personal / Programare / NetTuts / Elementele de bază ale scriptului BASH / surse $ ./fizzBuzz.sh -1 -1 -2 -2 -Fizz -Fizz -4 -4 -Buzz -Buzz -Fizz -Fizz -7 -7

După cum puteți vedea, totul este duplicat. Aceeași ieșire.

Pentru a doua soluție, am ales să atribuim mai întâi valoarea returnată unei variabile. În acea misiune, am folosit $ (), care, în acest caz, forks script-ul, execută codul și returnează ieșirea.


;, && și ||

Vă amintiți că am folosit punct și virgulă aici și acolo? Acestea pot fi folosite pentru a executa mai multe comenzi scrise pe aceeași linie. Dacă le separați prin punct și virgulă, acestea vor fi pur și simplu executate.

Un caz mai sofisticat este de a utiliza && între două comenzi. Da, aceasta este o logică AND; înseamnă că cea de-a doua comandă va fi executată numai dacă primul se întoarce Adevărat (iese din 0). Acest lucru este util; putem simplifica dacă declarații în acești concetățeni:

Funcția #! / bin / bash esteDivisibleBy return $ (($ 1% $ 2)) funcția fizzOrBuzz isDivisibleBy $ 1 3 && output = "Fizz" esteDivisibleBy $ 1 5 && output = "$ output Buzz" ]; apoi echo $ 1 altceva echo $ output; fi pentru numărul din 1 ... 100; face ecou "-'fizzOrBuzz $ number '' terminat

Ca funcție, isDivisibleBy returnează o valoare corespunzătoare retur, pe care o putem folosi ulterior && pentru a seta variabila dorită. Ce urmează && vor fi executate numai dacă condiția este Adevărat. În același mod, putem folosi || (caracter dublu) ca logic OR. Iată un exemplu rapid de mai jos.

csaba @ csaba ~ $ echo "bubu" || echo "bibi" bubu csaba @ csaba ~ $ echo false || echo "bibi" fals csaba @ csaba ~ $

Gândurile finale

Așa că face acest lucru pentru acest tutorial! Sper că ați luat o mână de sfaturi și tehnici noi pentru a vă scrie propriile scripturi Bash. Vă mulțumim pentru lectură și rămâneți reglați pentru articole mai avansate pe această temă.

Cod