De ce bucla for nu rulează într-un director. De ce bucla for nu este executată în directorul Loops în scripturile bash

Acasă / Nu se aprinde

Atenţie: Sunt beneficii ascunse în postare!

pentru bucle

Shell-ul bash acceptă bucle, care vă permit să repetați secvențe de valori. Iată structura de bază a unor astfel de bucle:

Pentru var în listă, comanda făcută

În fiecare iterație a buclei, următoarea valoare din listă va fi scrisă în variabila var. Prin urmare, prima trecere a buclei va folosi prima valoare din listă. În al doilea - al doilea și așa mai departe - până când bucla ajunge la ultimul element.

Iterarea peste valori simple

Poate cel mai simplu exemplu de buclă for în scripturile bash este repetarea unei liste de valori simple:

#!/bin/bash pentru var în prima secundă a treia a patra a cincea face echo Elementul $var terminat

Rezultatele acestui script sunt prezentate mai jos. Puteți vedea clar că variabila $var conține elemente din listă secvenţial. Acest lucru se întâmplă până când ciclul ajunge la ultimul dintre ele.



Simplu pentru buclă

Vă rugăm să rețineți că variabila $var își păstrează valoarea la ieșirea din buclă, conținutul ei poate fi schimbat și, în general, puteți lucra cu ea ca orice altă variabilă.

Iterarea peste valori complexe

Lista folosită pentru a inițializa bucla for poate conține nu numai șiruri simple formate dintr-un cuvânt, ci și fraze întregi care conțin mai multe cuvinte și semne de punctuație. De exemplu, ar putea arăta astfel:

#!/bin/bash pentru var în primul „al doilea” „al treilea” „O voi face” do echo „Acesta este: $var” gata

Acesta este ceea ce se întâmplă după ce această buclă trece prin listă. După cum puteți vedea, rezultatul este destul de așteptat.



Iterarea peste valori complexe
TNW-CUS-FMP - cod promoțional pentru o reducere de 10% la serviciile noastre, disponibil pentru activare în 7 zile"

Inițializarea unei bucle cu o listă obținută din rezultatele comenzii

O altă modalitate de a inițializa o buclă for este să îi transmiteți o listă, care este rezultatul unei comenzi. Aici, înlocuirea comenzilor este folosită pentru a le executa și a obține rezultatele muncii lor.

#!/bin/bash file="myfile" pentru var în $(cat $file) face echo " $var" gata

Acest exemplu folosește comanda cat, care citește conținutul unui fișier. Lista de valori rezultată este trecută în buclă și afișată pe ecran. Vă rugăm să rețineți că fișierul pe care îl accesăm conține o listă de cuvinte separate prin linii noi, nu sunt folosite spații.



O buclă care parcurge conținutul unui fișier

Aici trebuie să ținem cont de faptul că o astfel de abordare, dacă se preconizează o prelucrare a datelor rând cu linie, nu va funcționa pentru un fișier cu o structură mai complexă, ale cărui rânduri pot conține mai multe cuvinte separate prin spații. Bucla va procesa cuvinte individuale, nu linii.

Dacă nu este deloc ceea ce ai nevoie?

Separatoare de câmp

Motivul caracteristicii de mai sus este specialul variabila de mediu, care se numește IFS (Internal Field Separator) și vă permite să specificați separatori de câmp. În mod implicit, shell-ul bash consideră următoarele caractere separatoare de câmp:

  • Spaţiu
  • Caracter tabulator
  • Caracter de avans de linie

Dacă bash întâlnește oricare dintre aceste caractere în date, se presupune că este precedat de următoarea valoare independentă din listă.

Pentru a rezolva problema, puteți modifica temporar variabila de mediu IFS. Iată cum să o faceți într-un script bash, presupunând că aveți nevoie doar de o linie nouă ca separator de câmp:

IFS=$"n"

Odată ce adăugați această comandă la scriptul dvs. bash, va funcționa conform așteptărilor, ignorând spațiile și tabulatorii și tratând doar caracterele newline ca separatori de câmp.

#!/bin/bash file="/etc/passwd" IFS=$"n" pentru var în $(cat $fișier) face echo " $var" gata

Dacă acest script este rulat, va scoate exact ceea ce i se cere, oferind, în fiecare iterație a buclei, acces la următoarea linie scrisă în fișier.



Parcurgerea linie cu linie a unui fișier într-o buclă for

Separatorii pot fi și alte personaje. De exemplu, mai sus am afișat conținutul fișierului /etc/passwd. Datele utilizatorului de pe linii sunt separate prin două puncte. Dacă trebuie să procesați astfel de șiruri într-o buclă, IFS poate fi configurat astfel:

Parcurgerea fișierelor conținute într-un director

Una dintre cele mai frecvente utilizări ale buclelor for în scripturile bash este să traverseze fișierele situate într-un director și să proceseze acele fișiere.

De exemplu, iată cum să enumerați fișierele și folderele:

#!/bin/bash pentru fișierul din /home/likegeeks/* do if [ -d "$fișier" ] apoi echo "$fișierul este un director" elif [ -f "$fișier" ] apoi echo "$fișierul este un fișier" fi gata

Shell-ul bash acceptă bucle, care vă permit să repetați secvențe de valori. Iată structura de bază a unor astfel de bucle:

Pentru var în listă, comanda făcută
În fiecare iterație a buclei, următoarea valoare din listă va fi scrisă în variabila var. Prin urmare, prima trecere a buclei va folosi prima valoare din listă. În al doilea - al doilea și așa mai departe - până când bucla ajunge la ultimul element.

Iterarea peste valori simple

Poate cel mai simplu exemplu de buclă for în scripturile bash este repetarea unei liste de valori simple:

#!/bin/bash pentru var în prima secundă a treia a patra a cincea face echo Elementul $var terminat
Rezultatele acestui script sunt prezentate mai jos. Puteți vedea clar că variabila $var conține elemente din listă secvenţial. Acest lucru se întâmplă până când ciclul ajunge la ultimul dintre ele.


Simplu pentru buclă

Vă rugăm să rețineți că variabila $var își păstrează valoarea la ieșirea din buclă, conținutul ei poate fi schimbat și, în general, puteți lucra cu ea ca orice altă variabilă.

Iterarea peste valori complexe

Lista folosită pentru a inițializa bucla for poate conține nu numai șiruri simple formate dintr-un cuvânt, ci și fraze întregi care conțin mai multe cuvinte și semne de punctuație. De exemplu, ar putea arăta astfel:

#!/bin/bash pentru var în primul „al doilea” „al treilea” „O voi face” do echo „Acesta este: $var” gata
Acesta este ceea ce se întâmplă după ce această buclă trece prin listă. După cum puteți vedea, rezultatul este destul de așteptat.


Iterarea peste valori complexe
TNW-CUS-FMP - cod promoțional pentru o reducere de 10% la serviciile noastre, disponibil pentru activare în 7 zile"

Inițializarea unei bucle cu o listă obținută din rezultatele comenzii

O altă modalitate de a inițializa o buclă for este să îi transmiteți o listă, care este rezultatul unei comenzi. Aici înlocuirea comenzilor este folosită pentru a le executa și a obține rezultatele muncii lor.

#!/bin/bash file="myfile" pentru var în $(cat $file) face echo " $var" gata
Acest exemplu folosește comanda cat, care citește conținutul unui fișier. Lista de valori rezultată este trecută în buclă și afișată pe ecran. Vă rugăm să rețineți că fișierul pe care îl accesăm conține o listă de cuvinte separate prin linii noi, nu sunt folosite spații.


O buclă care parcurge conținutul unui fișier

Aici trebuie să ținem cont de faptul că o astfel de abordare, dacă se preconizează o prelucrare a datelor rând cu linie, nu va funcționa pentru un fișier cu o structură mai complexă, ale cărui rânduri pot conține mai multe cuvinte separate prin spații. Bucla va procesa cuvinte individuale, nu linii.

Dacă nu este deloc ceea ce ai nevoie?

Separatoare de câmp

Motivul pentru caracteristica de mai sus este o variabilă de mediu specială numită IFS (Internal Field Separator) care vă permite să specificați separatori de câmp. În mod implicit, shell-ul bash consideră următoarele caractere separatoare de câmp:
  • Spaţiu
  • Caracter tabulator
  • Caracter de avans de linie
Dacă bash întâlnește oricare dintre aceste caractere în date, se presupune că este precedat de următoarea valoare independentă din listă.

Pentru a rezolva problema, puteți modifica temporar variabila de mediu IFS. Iată cum să o faceți într-un script bash, presupunând că aveți nevoie doar de o linie nouă ca separator de câmp:

IFS=$"\n"
Odată ce adăugați această comandă la scriptul dvs. bash, va funcționa conform așteptărilor, ignorând spațiile și tabulatorii și tratând doar caracterele newline ca separatori de câmp.

#!/bin/bash file="/etc/passwd" IFS=$"\n" pentru var în $(cat $fișier) do echo " $var" gata
Dacă acest script este rulat, va scoate exact ceea ce i se cere, oferind, în fiecare iterație a buclei, acces la următoarea linie scrisă în fișier.


Parcurgerea linie cu linie a unui fișier într-o buclă for

Separatorii pot fi și alte personaje. De exemplu, mai sus am afișat conținutul fișierului /etc/passwd. Datele utilizatorului de pe linii sunt separate prin două puncte. Dacă trebuie să procesați astfel de șiruri într-o buclă, IFS poate fi configurat astfel:

Parcurgerea fișierelor conținute într-un director

Una dintre cele mai frecvente utilizări ale buclelor for în scripturile bash este să traverseze fișierele situate într-un director și să proceseze acele fișiere.

De exemplu, iată cum să enumerați fișierele și folderele:

#!/bin/bash pentru fișierul din /home/likegeeks/* do if [ -d "$fișier" ] apoi echo "$fișierul este un director" elif [ -f "$fișier" ] apoi echo "$fișierul este un fișier" fi terminat
Dacă ați trecut prin această serie de articole, ar trebui să înțelegeți structura construcției if-then, precum și cum să distingeți un fișier de un folder. Dacă vă este greu să înțelegeți codul de mai sus, recitiți acest material.

Acesta este ceea ce va scoate scriptul.


Afișarea conținutului unui folder

Observați cum inițializam bucla, și anume wildcardul „*” la sfârșitul adresei folderului. Acest simbol poate fi considerat ca un wildcard care înseamnă: „toate fișierele cu orice nume”. vă permite să organizați înlocuirea automată a numelor de fișiere care se potrivesc cu modelul.

Când testăm o condiție într-o instrucțiune if, includem numele variabilei între ghilimele. Acest lucru se face deoarece numele fișierului sau folderului poate conține spații.

C-style pentru bucle

Dacă sunteți familiarizat cu limbajul de programare C, sintaxa pentru descrierea buclelor bash for vă poate părea ciudată, deoarece sunteți, evident, obișnuit să descrieți buclele astfel:

Pentru (i = 0; i< 10; i++) { printf("number is %d\n", i); }
În scripturile bash puteți folosi buclele for, a căror descriere arată foarte asemănătoare cu buclele în stil C, deși există unele diferențe. Diagrama ciclului cu această abordare arată astfel:

Pentru ((valoarea inițială a variabilei; condiția pentru încheierea buclei; schimbarea variabilei))
În bash se poate scrie așa:

Pentru ((a = 1; a< 10; a++))
Iată un exemplu de lucru:

#!/bin/bash pentru ((i=1; i<= 10; i++)) do echo "number is $i" done
Acest cod va scoate o listă de numere de la 1 la 10.

Rularea unei bucle în stil C

buclă while

Construcția for nu este singura modalitate de a organiza buclele în scripturile bash. Puteți utiliza și buclele while aici. Într-o astfel de buclă, puteți specifica o comandă pentru a verifica o anumită condiție și a executa corpul buclei până când condiția testată returnează zero, sau un semnal pentru finalizarea cu succes a unei anumite operațiuni. Când condiția buclei returnează o valoare diferită de zero, ceea ce înseamnă o eroare, bucla se va opri.

Iată o diagramă a organizării buclelor while
în timp ce comanda de verificare a stării
do
alte echipe
făcut

Să aruncăm o privire la un exemplu de script cu o buclă ca aceasta:

#!/bin/bash var1=5 în timp ce [ $var1 -gt 0 ] face eco $var1 var1=$[ $var1 - 1 ] gata
La intrarea în buclă, se verifică dacă variabila $var1 este mai mare decât zero. Dacă da, se execută corpul buclei, în care se scade unul din valoarea variabilei. Acest lucru se întâmplă în fiecare iterație și imprimăm valoarea variabilei pe consolă înainte ca aceasta să fie modificată. De îndată ce $var1 atinge valoarea 0, bucla se oprește.

Rezultatul buclei while

Dacă nu modificați variabila $var1, acest lucru va face ca scriptul să ajungă într-o buclă infinită.

Bucle imbricate

Puteți utiliza orice comenzi din corpul buclei, inclusiv lansarea altor bucle. Astfel de construcții se numesc bucle imbricate:

#!/bin/bash pentru ((a = 1; a<= 3; a++)) do echo "Start $a:" for ((b = 1; b <= 3; b++)) do echo " Inner loop: $b" done done
Mai jos este ceea ce va afișa acest script. După cum puteți vedea, mai întâi se execută prima iterație a buclei exterioare, apoi trei iterații a celei interioare, după finalizarea acesteia intră din nou în joc bucla exterioară, apoi din nou cea interioară.

Bucle imbricate

Procesarea conținutului fișierului

Cel mai adesea, buclele imbricate sunt folosite pentru a procesa fișierele. Deci, bucla exterioară iterează peste liniile fișierului, iar cea interioară lucrează deja cu fiecare linie. Iată, de exemplu, cum arată procesarea fișierului /etc/passwd:

#!/bin/bash IFS=$"\n" pentru intrarea în $(cat /etc/passwd) face ecou "Valori în $entry –" IFS=: pentru valoarea în $entry face eco "$valoare" gata făcut
Există două bucle în acest script. Primul parcurge liniile folosind caracterul newline ca delimitator. Cel intern este ocupat cu analizarea șirurilor de caractere ale căror câmpuri sunt separate prin două puncte.

Procesarea datelor fișierului

Această abordare poate fi utilizată la procesarea fișierelor CSV sau a oricăror fișiere similare, prin scrierea caracterului delimitator în variabila de mediu IFS, după cum este necesar.

Managementul ciclului

Poate că, după intrarea în buclă, va trebui să o opriți atunci când variabila buclă atinge o anumită valoare care nu corespunde condiției specificate inițial pentru încheierea buclei. Într-o astfel de situație, va fi necesar să așteptăm finalizarea normală a ciclului? Bineînțeles că nu, și în astfel de cazuri următoarele două comenzi vor fi utile:
  • pauză
  • continua

comanda de pauză

Această comandă vă permite să întrerupeți execuția unei bucle. Poate fi folosit atât pentru bucle for și while:

#!/bin/bash pentru var1 în 1 2 3 4 5 6 7 8 9 10 do if [ $var1 -eq 5 ] apoi break fi echo "Number: $var1" done
O astfel de buclă, în condiții normale, va trece prin întreaga listă de valori din listă. Totuși, în cazul nostru, execuția sa va fi întreruptă atunci când variabila $var1 este egală cu 5.

Ieșirea devreme dintr-o buclă for

Iată același lucru, dar pentru bucla while:

#!/bin/bash var1=1 în timp ce [ $var1 -lt 10 ] do if [ $var1 -eq 5 ] apoi break fi echo "Iteration: $var1" var1=$(($var1 + 1)) done
Comanda break, executată când $var1 ajunge la 5, întrerupe bucla. Consola va afișa același lucru ca în exemplul anterior.

continua comanda

Când această comandă este întâlnită în corpul buclei, iterația curentă se termină devreme și începe următoarea, fără a ieși din buclă. Să ne uităm la comanda continue într-o buclă for:

#!/bin/bash pentru ((var1 = 1; var1< 15; var1++)) do if [ $var1 -gt 5 ] && [ $var1 -lt 10 ] then continue fi echo "Iteration number: $var1" done
Când condiția din interiorul buclei este îndeplinită, adică atunci când $var1 este mai mare de 5 și mai mic de 10, shell-ul execută comanda continue. Acest lucru duce la omiterea comenzilor rămase în corpul buclei și trecerea la următoarea iterație.

Comanda continue într-o buclă for

Procesarea ieșirii rulează într-o buclă

Ieșirea datelor dintr-o buclă poate fi procesată fie prin redirecționarea ieșirii, fie prin trecerea acesteia către o conductă. Acest lucru se face prin adăugarea comenzilor de procesare a ieșirii după instrucțiunea done.

De exemplu, în loc să afișați pe ecran ceea ce este scos într-o buclă, puteți scrie totul într-un fișier sau îl puteți transmite în altă parte:

#!/bin/bash pentru ((a = 1; a< 10; a++)) do echo "Number is $a" done >myfile.txt ecou „terminat”.
Shell-ul va crea fișierul myfile.txt și va redirecționa ieșirea instrucțiunii for către acel fișier. Să deschidem fișierul și să ne asigurăm că conține exact ceea ce ne așteptăm.

Redirecționează ieșirea buclei către fișier

Exemplu: Căutați fișiere executabile

Să folosim ceea ce am tratat deja și să scriem ceva util. De exemplu, dacă trebuie să aflați ce fișiere executabile sunt disponibile pe sistem, puteți scana toate folderele înregistrate în variabila de mediu PATH. Avem deja întregul arsenal de instrumente de care avem nevoie pentru asta, trebuie doar să le punem laolaltă:

#!/bin/bash IFS=: pentru folderul din $PATH, ecou „$folder:” pentru fișierul din $folder/* face if [ -x $file ] apoi echo „$file” fi gata
Un astfel de script, mic și necomplicat, ne-a permis să obținem o listă de fișiere executabile stocate în foldere de la PATH.

Căutarea fișierelor executabile în foldere din variabila PATH

Rezultate

Astăzi am vorbit despre buclele for și while din scripturile bash, cum să le rulăm și cum să le gestionăm. Acum știi cum să procesezi șiruri cu diferiți delimitatori în bucle, știi cum să redirecționezi datele de ieșire în bucle către fișiere, cum să vezi și să analizezi conținutul directoarelor.

Dacă presupunem că ești un dezvoltator de scripturi bash care știe despre ele doar ceea ce se spune în această serie de articole și în al doilea, atunci poți deja să scrii ceva util. Urmează a treia parte, după ce veți învăța cum să treceți parametrii și comutatoarele din linia de comandă la scripturi bash și ce să faceți cu toate acestea.

O scurtă descriere a diferenței dintre tipurile de bucle:

for - va efectua o acțiune atâta timp cât există obiecte de executat (de exemplu, citirea unui flux din stdin, un fișier sau o funcție);
în timp ce - execută acţiunea până când stare este adevărat;
până când - se va executa atâta timp cât stare nu va deveni adevărat, adică deocamdata este fals.

FOR Loop

Luați în considerare această versiune a scriptului cu o buclă:

$ cat loop.sh #!/bin/bash pentru variabila în `ls -1` do echo "$variable" gata

Sintaxa este foarte simplă și este arătată destul de clar în exemplu:

for (începe bucla) variabilă (declară o variabilă asupra căreia vom efectua acțiuni) în (trimite un flux în buclă) `ls -1` (comandă care urmează să fie executată și transmisă variabilei $variabile). Do și done sunt „corpul” buclei, în cadrul căruia principalele acțiuni vor fi efectuate asupra datelor primite, iar echo „$variable” este acțiunea reală efectuată de buclă.

Acum să schimbăm puțin exemplul și, în loc să specificăm în mod explicit comanda, vom folosi a doua variabilă:

$ cat loop.sh #!/bin/bash ls=`ls -1` pentru variabila din $ls do echo "$variable" gata

Acum comanda ls -1 este transmisă într-o variabilă separată, ceea ce vă permite să lucrați cu bucla mai flexibil. În loc de o variabilă într-o buclă, puteți utiliza și o funcție:

$ cat loop.sh #!/bin/bash lsl () ( ls -1 ) pentru variabila din `lsl` do echo "$variable" done

Condiția principală a buclei for este ca aceasta să fie executată atâta timp cât comanda transmisă acesteia conține obiecte pentru acțiune. Pe baza exemplului de mai sus - atâta timp cât ls -1 are fișiere de afișat - bucla le va transmite unei variabile și va executa „corpul buclei”. De îndată ce lista de fișiere din director se termină, bucla își va finaliza execuția.

Să facem exemplul puțin mai complicat.

Directorul conține o listă de fișiere:

$ ls -1 fișier1 fișier2 fișier3 fișier4 fișier5 buclă.sh nofile1 nofile2 nofile3 nofile4 nofile5

Trebuie să le selectăm dintre ei doar pe cei care nu au cuvântul " nu«:

$ cat loop.sh #!/bin/bash lsl=`ls -1` pentru variabila din $lsl do echo "$variable" | grep -v „nu” terminat $ ./loop.sh fișier1 fișier2 fișier3 fișier4 fișier5 buclă.sh

De asemenea, puteți utiliza expresii condiționate într-o buclă ( expresii condiționale) […] pentru a verifica condițiile și instrucțiunea break pentru a întrerupe bucla dacă condiția este declanșată.

Luați în considerare acest exemplu:

$ cat loop.sh #!/bin/bash lsl=`ls -1` pentru variabila din $lsl do if [ $variable != "loop.sh" ] then echo "$variable" | grep -v "nu" else break fi terminat

Bucla va continua până când este întâlnit fișierul loop.sh. De îndată ce execuția buclei ajunge la acest fișier, bucla va fi întreruptă de comanda break:

$ ./loop.sh fișier1 fișier2 fișier3 fișier4 fișier5

Un alt exemplu este utilizarea operațiilor aritmetice imediat înainte de a executa corpul buclei:

$ cat loop.sh #!/bin/bash pentru ((count=1; count<11; count++)) do echo "$count" done

Aici setăm trei comenzi de control - count=1, o condiție de control - în timp ce count este mai mică de 11 și o comandă de executat - count +1:

bucle WHILE și UNTIL

Un exemplu simplu care demonstrează clar cum funcționează bucla while:

$ cat loop.sh #!/bin/bash count=0 while [ $count -lt 10 ] do ((count++)) echo $count done

Setăm variabila $count la zero și apoi rulăm bucla whi cu condiția „în timp ce $count este mai mic de zece, executam bucla”. În corpul buclei executăm increment postfix+1 la variabila $count și rezultatul este tipărit în stdout.

Rezultatul executiei:

$ ./loop.sh 1 2 3 4 5 6 7 8 9 10

De îndată ce valoarea variabilei $count a devenit 10, bucla s-a oprit.

Un bun exemplu de buclă „infinită” care demonstrează cum funcționează while:

$ cat loop.sh #!/bin/bash count=10 while [ 1 = 1 ] do ((count++)) echo $count done $ ./loop.sh ... 5378 5379 5380 5381 5382 5383 ^C

Bucla până funcționează în mod similar, dar în direcția opusă:

$ cat loop.sh #!/bin/bash count=0 până la [ $count -gt 10 ] do ((count++)) echo $count terminat

Aici setăm o condiție similară, dar în loc de „în timp ce variabila este mai mică de 10”, specificăm „până când variabila devine mai mare de 10”. Rezultatul executiei:

$ ./loop.sh 1 2 3 4 5 6 7 8 9 10 11

Dacă exemplul de mai sus de „buclă fără sfârșit” este executat folosind până, nu va scoate nimic, spre deosebire de while:

$ cat loop.sh #!/bin/bash count=10 până la [ 1 = 1 ] do ((count++)) echo $count done $ ./loop.sh $

pentru ca" stare» inițial « adevărat„—corpul buclei nu va fi executat.

La fel ca în bucla for, puteți folosi funcții în while și until. De exemplu, o buclă dintr-un script real care verifică starea serverului Motan(PID este preluat din sistem SLES, poate diferi în alte sisteme), o versiune ușor simplificată:

$ cat loop.sh #!/bin/bash check_tomcat_status () ( RUN=`ps aux | grep tomcat | grep -v grep | grep java | awk "(printează $2)"` ) în timp ce check_tomcat_status do if [ -n "$ RUN" ] apoi printf "AVERTISMENT: Tomcat încă rulează cu PID $RUN."

Rezultatul executiei:

else printf "Tomcat s-a oprit, continuă... nn" break fi done

$ ./loop.sh AVERTISMENT: Tomcat încă rulează cu PID 14435 26548. AVERTISMENT: Tomcat încă rulează cu PID 14435 26548. AVERTISMENT: Tomcat încă rulează cu PID 14435 26548. AVERTISMENT: Tomcat încă rulează cu PID 14435 26548. rulează cu PID 14435 26548. AVERTISMENT: Tomcat încă rulează cu PID 14435 26548. AVERTISMENT: Tomcat încă rulează cu PID 14435 26548. AVERTISMENT: Tomcat încă rulează cu PID 14435

Versiunea completă:

Check_tomcat_status () ( RUN=`ps aux | grep tomcat | grep -v grep | grep java | awk "(print $2)"` ) în timp ce verificați_tomcat_status; face if [ -n "$RUN" ] then printf "AVERTISMENT: Tomcat încă rulează cu PID $RUN. Oprește-l? " răspunde la "Oprirea Tomcat..." "Se continuă instalarea..." && $CATALINA_HOME/bin/shutdown sh 2&>1 /dev/null || întrerupe somnul 2 dacă [ -n "$RUN" ] apoi printf "Tomcat încă rulează. Omorâți-l? " răspunde "Killing Tomcat..." "Se continuă instalarea...n" && kill $RUN || break sleep 2 fi else printf "Tomcat oprit, continuă... nn" break fi terminat

Funcția de răspuns a fost descrisă în articol, dar aici este folosită o versiune ușor îmbunătățită:

Răspuns () ( în timp ce se citește răspunsul; face eco caz $răspuns în |) printf "$1n" return 0 break ;;

5

|) printf "$2n" returnează 1 pauză ;;

*) printf "Vă rugăm, introduceți Y(da) sau N(nu)!" esac done )

Aici a fost posibil să se folosească atât while, cât și până - dar nu o buclă for, deoarece for ar fi funcționat o dată (a primit PID-ul și s-a încheiat).

1) Scriptul tău este codificat într-un mod periculos. În primul rând, presupun că utilizați shell-ul Bash, deoarece l-ați marcat cu „/bash” și „/for”.În răspunsul meu, voi cita acest excelent ghid Bash, care este probabil cea mai bună sursă pentru a învăța Bash.

Mai exact vorbind, $(find$ DIRWORK -type d -name work) și $(find$ DIR -type f) vor suferi împărțirea cuvintelor, astfel dacă find găsește un fișier cu spații în numele său, adică rezultatul împărțirii cuvintelor „nume fișier” Bash va transmite 2 argumente la comanda for pentru a itera, adică unul pentru „fișier” și unul pentru „nume”. În acest caz, doriți să sperați că veți obține „fișier: niciun astfel de fișier sau director” și „nume: niciun astfel de fișier sau director” în loc să le deteriorați dacă există efectiv.

2) Prin convenție, variabilele de mediu (PATH, EDITOR, SHELL, ...) și variabilele interne de shell (BASH_VERSION, RANDOM, ...) sunt scrise cu majuscule. Toate celelalte nume de variabile trebuie să fie cu litere mici. Deoarece numele variabilelor țin cont de majuscule și minuscule, această convenție evită înlocuirea accidentală a variabilelor de mediu și interne.

Aceasta este o versiune mai sigură a scriptului dvs., pe care vă recomand să o utilizați în schimb:

My_home="/root/mydir" my_dir=" $my_home/var" dir_work="$ my_home/Local" în timp ce IFS= citește -r -d "" f; nu # Bănuiesc că doriți să ignorați și stderr; # de aici a venit 2>&1. dacă lsof -n " ​​​​$f" | grep "" > /dev/null 2> atunci ecou "hei , eu "Sunt mai în siguranță acum!"< <(find "$ dir_work" -type f -print0) while IFS= read -r -d "" f; do echo "2" done < <(find "$dir_work" -type d -name "work" -print0)

fi gata

După cum puteți vedea, variabila IFS este setată la gol, împiedicând astfel citirea să reducă spațiul din față și din spate de la linie. Comanda de citire folosește linia goală (-d "") ca delimitator pentru a citi până când ajunge la a\0 find trebuie să fie m în consecință, așa că folosește opțiunea -print0 pentru a-și delimita datele cu \0 în loc de o linie nouă. , în mod surprinzător și rău intenționat, poate face parte din numele fișierului. Împărțirea unui astfel de fișier \n în două părți va rupe codul nostru.

Răspunsul anterior care spunea că constatare... | în timp ce se citește numele; face...; done ar trebui să fie folosit pentru a citi ieșirea găsiți poate fi de asemenea proastă. Bucla while rulează într-un nou subshell cu propria sa copie a variabilelor copiate din părintele său. Această copie este apoi folosită pentru orice doriți. Când bucla while este terminată, copia subshell va fi renunțată și variabilele originale ale părintelui nu vor fi modificate.

0

„Nu utilizați niciodată înlocuirea comenzilor, de niciun fel, fără ghilimele.” Acest lucru este doar nimerit, dar este posibil să utilizați înlocuirea comenzilor fără ghilimele atunci când setați o variabilă: „something = $(basename” filename cu spații „)”. - Smith John 22 apr 13 22-04-2013 21:43:10

2

Pentru i în $(find$ DIRWORK -type d -name work); face ecoul „2” gata

va fi primul care execută această linie

Găsiți $DIRWORK -type d -name work

așteptați până când find se termină de execuție și apoi luați o zi liberă și puneți-o înapoi în bucla for

Pentru i în rezultatul find; face ecoul „2” gata

numai atunci bucla for va începe să se execute.

Deci, dacă găsirea durează mult timp pentru a-și termina bucla for, trebuie să aștepte mult înainte de a putea începe.

Încercați interactiv comenzile de căutare temporare

$ time find $DIRWORK -type d -name work

și vezi cât durează.

De asemenea, rețineți: nu ar trebui să utilizați o buclă for pentru a repeta peste numele fișierelor. Utilizați o buclă while cu citire astfel:

Find$ DIRWORK -type d -name work | în timp ce se citește numele; face ecoul „2” gata

Bonus: rulează o buclă while în paralel cu find . Aceasta înseamnă că bucla while va finaliza o iterație de îndată ce find printează o linie. Nu este nevoie să așteptați găsirea pentru a finaliza execuția.

În această prelegere continuăm să ne cunoaștem bash. Aș dori să vă reamintesc că luăm în considerare aceste elemente bash, care ne va ajuta să înțelegem scripturile sistemului de operare. Astfel de elemente sunt cu siguranță bucle și funcții. Dacă cineva a studiat programarea, atunci nu vor fi dificultăți în înțelegerea acestor întrebări.

pentru buclă

Ciclu pentru V bash are două tipuri. Să ne uităm mai întâi la versiunea clasică pentru. Vederea generală este următoarea:

Între elemente pentruŞi în este setată o variabilă, care la rândul ei ia o valoare din succesiunea de valori specificată între înŞi do. Între doŞi făcut există comenzi care sunt executate de fiecare dată când o variabilă își schimbă valoarea. Bucla se oprește când variabila ia ultima valoare din secvență. Valorile din secvență sunt separate prin spații.

Iată un exemplu practic:

Secvența valorilor poate fi specificată în moduri diferite. În mod explicit - ca în exemplul de mai sus, sau folosind alte variabile, sau folosind comenzi speciale. Să ne uităm la câteva exemple. Deoarece valorile sunt specificate separate prin spații, astfel de valori pot fi orice variabilă care conține un șir cu spații:

Rezultatul va fi același ca în primul exemplu.

Dacă trebuie să specificați o secvență de numere, puteți utiliza comanda secvși un mecanism de substituție. Echipă secv returnează o secvență de valori numerice pe ecran. Sintaxa este simplă și va fi clară din exemplul de mai jos:

Rezultat:

Să revenim la al doilea tip pentru. Adesea, în scripturi puteți găsi așa-numita variantă C-like pentru, care este folosit pentru bucle bazate pe numere. Să aruncăm o privire la un exemplu:

Bucla rulează atâta timp cât condiția testată în expresie este adevărată. De îndată ce expresia revine false, execuția buclei se oprește.

Exemplu practic:

#!/bin/bash
i=1
în timp ce [ $i -lt 7 ]
do
eco $i
fie i=i+1
făcut

În exemplul nostru, verificăm că variabila i este mai mică decât (-lt) numărul 7 și dacă da, atunci valoarea variabilei este afișată pe ecran. Expresie fie i=i+1, crește variabila cu una, verifică din nou etc. let îi spune interpretului că argumentele ar trebui să fie recunoscute ca valori numerice. Această linie ar putea fi scrisă ca lasă i++(varianta asemanatoare c). Când un număr crește cu mai mult de unul, se poate scrie astfel: fie i+=2- în acest caz i va crește în trepte de 2. O altă opțiune pentru creșterea unei variabile este utilizarea calculatorului încorporat (funcționează numai cu numere întregi). Calculatorul poate fi accesat prin paranteze duble: i=$(($i+1)) sau prin pătrate: i=$[$i+1] De asemenea, puteți utiliza calculatorul pe linia de comandă:

Trebuie să fii atent la bucle pentru a nu ajunge la o buclă nesfârșită. Apropo pentru depanare bash scripturi în care puteți schimba prima linie #!/bin/bash -x sau rulați scriptul cu comanda bash -x:

igor@ubuntu:~/linux$ bash -x ./testfor.sh
+ i=1
+ „[‘ 1 -gt 5 „]”
+ ecou i=1
i=1
+ fie i=i+1
+ „[‘ 2 -gt 5 „]”
+ ecou i=2
i=2
+ fie i=i+1
+ „[‘ 3 -gt 5 „]”
+ ecou i=3
i=3
+ fie i=i+1
+ „[‘ 4 -gt 5 „]”
+ echo i=4
i=4
+ fie i=i+1
+ „[‘ 5 -gt 5 ‘]’
+ ecou i=5
i=5
+ fie i=i+1
+ „[‘ 6 -gt 5 ‘]’

Asigurați-vă că exersați scrierea de scripturi mici pentru a vă consolida înțelegerea modului în care funcționează buclele bash.

Funcții în bash

Funcțiile sunt utilizate în bash foarte lat. Funcțiile sunt descrise în două moduri: cu un cuvânt cheie funcţie, și fără el.

Prima cale:

funcția nume_funcție
{
organismul funcțional
}

A doua cale:

nume_funcție()
{
organismul funcțional
}

O funcție este numită pe nume oriunde în script, dar numai după ce a fost descrisă funcția în sine. Funcțiilor pot fi transmise și parametri, care sunt specificați separați printr-un spațiu după apelul funcției (nume). Să ne uităm la un exemplu de script bash:

#!/bin/bash
grund de funcţii
{
dacă [ $# -ne 0 ]
apoi
local a=1
echo "Numărul de parametri trecuți - $#"
pentru eu in $@
do
echo „$a-al-lea parametru este $i”
lasă a++
făcut
întoarce 0
altfel
echo „Parametrii nu au fost trecuți”
întoarce 1
fi
}
echo „Apelați o funcție cu parametri:”
grund a b c
eco $?
echo „Apelați o funcție fără parametri:”
grund
eco $?

În acest exemplu, o funcție numită grund. Apelarea unei funcții cu parametri: grund a b c si fara parametri: grund. În corpul funcției, toate construcțiile ar trebui să vă fie familiare, cu excepția $# , $iŞi $@ .$# — returnează numărul de parametri trecuți funcției. În exemplul nostru acesta va fi un număr 3 .$@ returnează toți parametrii într-o singură linie. În exemplu ar fi a b c. Și prin $1 , $2 , $3 etc. Puteți accesa fiecare parametru individual. $? — conține codul de execuție al ultimei comenzi. În exemplul nostru, codul de execuție al funcției.

Funcția poate returna și o valoare numerică printr-un cuvânt cheie reveni. De obicei, returnează 0 dacă funcția a fost executată fără erori sau o valoare diferită de zero dacă ceva a mers prost. În exemplu, dacă o funcție este apelată cu parametri, se returnează valoarea 0, iar dacă funcția a fost apelată fără parametri, se returnează codul 1.

Totul despre transmiterea parametrilor unei funcții funcționează exact la fel pentru un script. De asemenea, puteți transmite parametri scriptului și îi puteți manipula în același mod folosind $#, $@, $N. Din aceeași categorie este opțiunea - $0 - care returnează numele comenzii care a lansat scriptul. Dacă scriptul a fost rulat prin comandă ./script.sh, apoi ecou $0 va returna valoarea ./script.sh, iar dacă la comandă /home/igor/linux/script.sh, atunci valoarea va fi returnată /home/igor/linux/script.sh.

© 2024 ermake.ru -- Despre repararea PC-ului - Portal de informații