Dlaczego pętla for nie działa w katalogu. Dlaczego pętla for nie jest wykonywana w katalogu Loops w skryptach bash

Dom / Nie włącza się

Uwaga: W poście kryją się korzyści!

dla pętli

Powłoka bash obsługuje pętle for, które umożliwiają iterację po sekwencjach wartości. Oto podstawowa struktura takich pętli:

Dla var na liście wykonaj polecenie

W każdej iteracji pętli kolejna wartość z listy będzie zapisywana do zmiennej var. Dlatego w pierwszym przebiegu pętli zostanie użyta pierwsza wartość z listy. W drugim - drugim i tak dalej - aż pętla dotrze do ostatniego elementu.

Iterowanie po prostych wartościach

Być może najprostszym przykładem pętli for w skryptach bash jest iteracja po liście prostych wartości:

#!/bin/bash dla var w pierwszej, drugiej, trzeciej, czwartej, piątej, wykonaj echo Element $var został wykonany

Wyniki działania tego skryptu pokazano poniżej. Wyraźnie widać, że zmienna $var zawiera elementy z listy sekwencyjnie. Dzieje się tak, dopóki cykl nie dotrze do ostatniego z nich.



Prosta pętla for

Należy pamiętać, że zmienna $var zachowuje swoją wartość po wyjściu z pętli, jej zawartość można zmieniać i ogólnie rzecz biorąc, można z nią pracować jak z każdą inną zmienną.

Iterowanie po wartościach złożonych

Lista używana do inicjowania pętli for może zawierać nie tylko proste ciągi znaków składające się z jednego słowa, ale także całe frazy zawierające kilka słów i znaków interpunkcyjnych. Na przykład może to wyglądać tak:

#!/bin/bash dla var w pierwszym „drugim” „trzecim” „Zrobię to” do echo „To jest: $var” zrobione

Tak się dzieje, gdy ta pętla przejdzie przez listę. Jak widać, wynik jest całkiem oczekiwany.



Iterowanie po wartościach złożonych
TNW-CUS-FMP - kod promocyjny na 10% rabatu na nasze usługi, dostępny do aktywacji w ciągu 7 dni"

Inicjowanie pętli z listą uzyskaną z wyników polecenia

Innym sposobem zainicjowania pętli for jest przekazanie jej listy będącej wynikiem polecenia. Tutaj stosuje się podstawienie poleceń, aby je wykonać i uzyskać wyniki ich pracy.

#!/bin/bash file="myfile" dla var w $(cat $file) wykonaj echo "$var" zrobione

W tym przykładzie użyto polecenia cat, które odczytuje zawartość pliku. Powstała lista wartości jest przekazywana do pętli i wyświetlana na ekranie. Należy pamiętać, że plik, do którego uzyskujemy dostęp, zawiera listę słów oddzielonych znakami nowej linii; nie używa się spacji.



Pętla, która przegląda zawartość pliku

Tutaj musimy wziąć pod uwagę, że takie podejście, jeśli oczekujemy przetwarzania danych linia po linii, nie sprawdzi się w przypadku pliku o bardziej złożonej strukturze, którego wiersze mogą zawierać kilka słów oddzielonych spacjami. Pętla przetwarza pojedyncze słowa, a nie linie.

A jeśli to wcale nie jest to, czego potrzebujesz?

Separatory pól

Powyższa funkcja jest wyjątkowa zmienna środowiskowa, który nosi nazwę IFS (Internal Field Separator) i umożliwia określenie separatorów pól. Domyślnie powłoka bash traktuje następujące znaki jako separatory pól:

  • Przestrzeń
  • Znak tabulatora
  • Znak nowego wiersza

Jeśli bash napotka w danych którykolwiek z tych znaków, zakłada, że ​​jest on poprzedzony następną niezależną wartością na liście.

Aby rozwiązać ten problem, możesz tymczasowo zmienić zmienną środowiskową IFS. Oto jak to zrobić w skrypcie bash, zakładając, że potrzebujesz tylko znaku nowej linii jako separatora pól:

IFS=$"n"

Po dodaniu tego polecenia do skryptu bash będzie ono działać zgodnie z oczekiwaniami, ignorując spacje i tabulatory oraz traktując tylko znaki nowej linii jako separatory pól.

#!/bin/bash file="/etc/passwd" IFS=$"n" dla var w $(cat $file) wykonaj echo " $var" zrobione

Jeśli ten skrypt zostanie uruchomiony, wyświetli dokładnie to, czego się od niego wymaga, dając w każdej iteracji pętli dostęp do następnej linii zapisanej w pliku.



Przechodzenie pliku linia po linii w pętli for

Separatorami mogą być także inne znaki. Dla przykładu powyżej wyświetliliśmy zawartość pliku /etc/passwd. Dane użytkownika w wierszach oddzielane są dwukropkami. Jeśli chcesz przetwarzać takie ciągi w pętli, IFS można skonfigurować w następujący sposób:

Przechodzenie plików zawartych w katalogu

Jednym z najczęstszych zastosowań pętli for w skryptach bash jest przeglądanie plików znajdujących się w katalogu i przetwarzanie tych plików.

Oto jak na przykład wyświetlić listę plików i folderów:

#!/bin/bash dla pliku w /home/likegeeks/* wykonaj if [ -d "$plik" ] następnie echo "$plik to katalog" elif [ -f "$plik"] następnie echo "$plik to katalog plik" i gotowe

Powłoka bash obsługuje pętle for, które umożliwiają iterację po sekwencjach wartości. Oto podstawowa struktura takich pętli:

Dla var na liście wykonaj polecenie
W każdej iteracji pętli kolejna wartość z listy będzie zapisywana do zmiennej var. Dlatego w pierwszym przebiegu pętli zostanie użyta pierwsza wartość z listy. W drugim - drugim i tak dalej - aż pętla dotrze do ostatniego elementu.

Iterowanie po prostych wartościach

Być może najprostszym przykładem pętli for w skryptach bash jest iteracja po liście prostych wartości:

#!/bin/bash dla var w pierwszej, drugiej, trzeciej, czwartej, piątej, wykonaj echo Element $var został wykonany
Wyniki działania tego skryptu pokazano poniżej. Wyraźnie widać, że zmienna $var zawiera elementy z listy sekwencyjnie. Dzieje się tak, dopóki cykl nie dotrze do ostatniego z nich.


Prosta pętla for

Należy pamiętać, że zmienna $var zachowuje swoją wartość po wyjściu z pętli, jej zawartość można zmieniać i ogólnie rzecz biorąc, można z nią pracować jak z każdą inną zmienną.

Iterowanie po wartościach złożonych

Lista używana do inicjowania pętli for może zawierać nie tylko proste ciągi znaków składające się z jednego słowa, ale także całe frazy zawierające kilka słów i znaków interpunkcyjnych. Na przykład może to wyglądać tak:

#!/bin/bash dla var w pierwszym „drugim” „trzecim” „Zrobię to” do echo „To jest: $var” zrobione
Tak się dzieje, gdy ta pętla przejdzie przez listę. Jak widać, wynik jest całkiem oczekiwany.


Iterowanie po wartościach złożonych
TNW-CUS-FMP - kod promocyjny na 10% rabatu na nasze usługi, dostępny do aktywacji w ciągu 7 dni"

Inicjowanie pętli z listą uzyskaną z wyników polecenia

Innym sposobem zainicjowania pętli for jest przekazanie jej listy będącej wynikiem polecenia. Tutaj stosuje się podstawienie poleceń, aby je wykonać i uzyskać wyniki ich pracy.

#!/bin/bash file="myfile" dla var w $(cat $file) wykonaj echo "$var" zrobione
W tym przykładzie użyto polecenia cat, które odczytuje zawartość pliku. Powstała lista wartości jest przekazywana do pętli i wyświetlana na ekranie. Należy pamiętać, że plik, do którego uzyskujemy dostęp, zawiera listę słów oddzielonych znakami nowej linii; nie używa się spacji.


Pętla, która przegląda zawartość pliku

Tutaj musimy wziąć pod uwagę, że takie podejście, jeśli oczekujemy przetwarzania danych linia po linii, nie sprawdzi się w przypadku pliku o bardziej złożonej strukturze, którego wiersze mogą zawierać kilka słów oddzielonych spacjami. Pętla przetwarza pojedyncze słowa, a nie linie.

A jeśli to wcale nie jest to, czego potrzebujesz?

Separatory pól

Powodem powyższej funkcji jest specjalna zmienna środowiskowa o nazwie IFS (Internal Field Separator), która pozwala określić separatory pól. Domyślnie powłoka bash traktuje następujące znaki jako separatory pól:
  • Przestrzeń
  • Znak tabulatora
  • Znak nowego wiersza
Jeśli bash napotka w danych którykolwiek z tych znaków, zakłada, że ​​jest on poprzedzony następną niezależną wartością na liście.

Aby rozwiązać ten problem, możesz tymczasowo zmienić zmienną środowiskową IFS. Oto jak to zrobić w skrypcie bash, zakładając, że potrzebujesz tylko znaku nowej linii jako separatora pól:

IFS=$"\n"
Po dodaniu tego polecenia do skryptu bash będzie ono działać zgodnie z oczekiwaniami, ignorując spacje i tabulatory oraz traktując tylko znaki nowej linii jako separatory pól.

#!/bin/bash file="/etc/passwd" IFS=$"\n" dla var w $(cat $file) wykonaj echo " $var" zrobione
Jeśli ten skrypt zostanie uruchomiony, wyświetli dokładnie to, czego się od niego wymaga, dając w każdej iteracji pętli dostęp do następnej linii zapisanej w pliku.


Przechodzenie pliku linia po linii w pętli for

Separatorami mogą być także inne znaki. Dla przykładu powyżej wyświetliliśmy zawartość pliku /etc/passwd. Dane użytkownika w wierszach oddzielane są dwukropkami. Jeśli chcesz przetwarzać takie ciągi w pętli, IFS można skonfigurować w następujący sposób:

Przechodzenie plików zawartych w katalogu

Jednym z najczęstszych zastosowań pętli for w skryptach bash jest przeglądanie plików znajdujących się w katalogu i przetwarzanie tych plików.

Oto jak na przykład wyświetlić listę plików i folderów:

#!/bin/bash dla pliku w /home/likegeeks/* wykonaj if [ -d "$plik" ] następnie echo "$plik to katalog" elif [ -f "$plik"] następnie echo "$plik to katalog plik" i gotowe
Jeśli przeczytałeś tę serię artykułów, powinieneś zrozumieć strukturę konstrukcji if-then, a także dowiedzieć się, jak odróżnić plik od folderu. Jeżeli zrozumienie powyższego kodu sprawia Ci trudność, przeczytaj ponownie ten materiał.

To właśnie wyświetli skrypt.


Wyświetlanie zawartości folderu

Zwróć uwagę, jak inicjujemy pętlę, a mianowicie symbol wieloznaczny „*” na końcu adresu folderu. Ten symbol można traktować jako symbol wieloznaczny: „wszystkie pliki o dowolnych nazwach”. pozwala na zorganizowanie automatycznego podstawienia nazw plików pasujących do wzorca.

Testując warunek w instrukcji if, nazwę zmiennej ujmujemy w cudzysłów. Dzieje się tak, ponieważ nazwa pliku lub folderu może zawierać spacje.

Pętle w stylu C

Jeśli znasz język programowania C, składnia opisu pętli bash for może wydawać Ci się dziwna, ponieważ najwyraźniej jesteś przyzwyczajony do opisywania pętli w ten sposób:

Dla (i = 0; tj< 10; i++) { printf("number is %d\n", i); }
W skryptach basha można używać pętli for, których opis wygląda bardzo podobnie do pętli w stylu C, chociaż są pewne różnice. Schemat cyklu przy tym podejściu wygląda następująco:

For ((wartość początkowa zmiennej; warunek zakończenia pętli; zmiana zmiennej))
W bashu można to zapisać w ten sposób:

Dla ((a = 1; a< 10; a++))
Oto działający przykład:

#!/bin/bash for ((i=1; tj<= 10; i++)) do echo "number is $i" done
Ten kod wyświetli listę liczb od 1 do 10.

Uruchamianie pętli w stylu C

pętla while

Konstrukcja for nie jest jedynym sposobem organizowania pętli w skryptach bash. Można tu także użyć pętli while. W takiej pętli można podać polecenie sprawdzające określony warunek i wykonywać treść pętli do momentu, aż sprawdzany warunek zwróci zero lub sygnał pomyślnego zakończenia określonej operacji. Gdy warunek pętli zwróci wartość różną od zera, co oznacza błąd, pętla zostanie zatrzymana.

Oto schemat organizacji pętli while
podczas wykonywania polecenia sprawdzania warunku
Do
inne zespoły
zrobione

Przyjrzyjmy się przykładowemu skryptowi z pętlą taką jak ta:

#!/bin/bash var1=5 while [ $var1 -gt 0 ] wykonaj echo $var1 var1=$[ $var1 - 1 ] zrobione
Na wejściu do pętli sprawdzane jest czy zmienna $var1 jest większa od zera. Jeżeli tak, wykonywany jest korpus pętli, w którym od wartości zmiennej odejmuje się jeden. Dzieje się tak w każdej iteracji i wypisujemy wartość zmiennej na konsoli, zanim zostanie ona zmodyfikowana. Gdy tylko $var1 osiągnie wartość 0, pętla zatrzymuje się.

Wynik pętli while

Jeśli nie zmodyfikujesz zmiennej $var1, spowoduje to, że skrypt zakończy się w nieskończonej pętli.

Zagnieżdżone pętle

W treści pętli można używać dowolnych poleceń, łącznie z uruchamianiem innych pętli. Takie konstrukcje nazywane są pętlami zagnieżdżonymi:

#!/bin/bash for ((a = 1; a<= 3; a++)) do echo "Start $a:" for ((b = 1; b <= 3; b++)) do echo " Inner loop: $b" done done
Poniżej znajduje się to, co wyświetli ten skrypt. Jak widać, najpierw wykonywana jest pierwsza iteracja pętli zewnętrznej, następnie trzy iteracje wewnętrznej, po jej zakończeniu ponownie wchodzi w grę pętla zewnętrzna, a następnie ponownie wewnętrzna.

Zagnieżdżone pętle

Przetwarzanie zawartości pliku

Najczęściej do przetwarzania plików wykorzystywane są pętle zagnieżdżone. Zatem zewnętrzna pętla iteruje po liniach pliku, a wewnętrzna już pracuje z każdą linią. Oto na przykład jak wygląda przetwarzanie pliku /etc/passwd:

#!/bin/bash IFS=$"\n" dla wpisu w $(cat /etc/passwd) wykonaj echo "Wartości w $wpisie –" IFS=: dla wartości w $wpisie wykonaj echo "$wartość" zrobione zrobione
W tym skrypcie znajdują się dwie pętle. Pierwszy z nich przechodzi przez linie, używając znaku nowej linii jako ogranicznika. Wewnętrzny jest zajęty analizowaniem ciągów znaków, których pola oddzielane są dwukropkami.

Przetwarzanie danych plików

Podejścia tego można użyć podczas przetwarzania plików CSV lub innych podobnych plików, w razie potrzeby zapisując znak ogranicznika w zmiennej środowiskowej IFS.

Zarządzanie cyklem

Być może po wejściu do pętli będziesz musiał ją zatrzymać, gdy zmienna pętli osiągnie pewną wartość, która nie odpowiada początkowo określonemu warunkom zakończenia pętli. Czy w takiej sytuacji trzeba będzie poczekać na normalne zakończenie cyklu? Oczywiście, że nie i w takich przypadkach przydadzą się dwa poniższe polecenia:
  • przerwa
  • Kontynuować

polecenie przerwania

Polecenie to umożliwia przerwanie wykonywania pętli. Można jej używać zarówno w pętlach for, jak i while:

#!/bin/bash dla var1 in 1 2 3 4 5 6 7 8 9 10 wykonaj if [ $var1 -eq 5 ], a następnie przerwa fi echo "Numer: $var1" zrobione
Taka pętla w normalnych warunkach przejdzie przez całą listę wartości z listy. Jednak w naszym przypadku jego wykonanie zostanie przerwane, gdy zmienna $var1 będzie równa 5.

Wczesne wyjście z pętli for

Tutaj jest to samo, ale dla pętli while:

#!/bin/bash var1=1 while [ $var1 -lt 10 ] wykonaj if [ $var1 -eq 5 ] następnie przerwa fi echo "Iteracja: $var1" var1=$(($var1 + 1)) gotowe
Polecenie break, wykonane, gdy $var1 osiągnie wartość 5, przerywa pętlę. Konsola wyświetli to samo, co w poprzednim przykładzie.

kontynuuj polecenie

Kiedy to polecenie zostanie napotkane w treści pętli, bieżąca iteracja kończy się wcześniej i rozpoczyna następna, bez wychodzenia z pętli. Przyjrzyjmy się poleceniukontynuuj w pętli for:

#!/bin/bash for ((var1 = 1; var1< 15; var1++)) do if [ $var1 -gt 5 ] && [ $var1 -lt 10 ] then continue fi echo "Iteration number: $var1" done
Gdy warunek wewnątrz pętli jest spełniony, to znaczy, gdy zmienna $1 jest większa niż 5 i mniejsza niż 10, powłoka wykonuje polecenie kontynuowania. Powoduje to pominięcie pozostałych poleceń w treści pętli i przejście do następnej iteracji.

Poleceniekontynuuj w pętli for

Przetwarzanie danych wyjściowych działa w pętli

Dane wyjściowe z pętli można przetwarzać poprzez przekierowanie danych wyjściowych lub przekazanie ich do potoku. Odbywa się to poprzez dodanie poleceń przetwarzania danych wyjściowych po instrukcji Does.

Na przykład, zamiast pokazywać na ekranie to, co zostanie wyprowadzone w pętli, możesz zapisać to wszystko do pliku lub przekazać gdzie indziej:

#!/bin/bash for ((a = 1; a< 10; a++)) do echo "Number is $a" done >mójplik.txt echo „zakończono”.
Powłoka utworzy plik myfile.txt i przekieruje dane wyjściowe instrukcji for do tego pliku. Otwórzmy plik i upewnijmy się, że zawiera dokładnie to, czego oczekujemy.

Przekieruj wyjście pętli do pliku

Przykład: Wyszukaj pliki wykonywalne

Wykorzystajmy to, co już omówiliśmy i napiszmy coś przydatnego. Na przykład, jeśli chcesz dowiedzieć się, które pliki wykonywalne są dostępne w systemie, możesz przeskanować wszystkie foldery zapisane w zmiennej środowiskowej PATH. Mamy już cały arsenał potrzebnych do tego narzędzi, pozostaje nam tylko złożyć to wszystko w jedną całość:

#!/bin/bash IFS=: dla folderu w $PATH wykonaj echo "$folder:" dla pliku w $folder/* wykonaj if [ -x $plik ] następnie echo " $plik" i gotowe
Taki skrypt, mały i nieskomplikowany, pozwolił nam uzyskać listę plików wykonywalnych przechowywanych w folderach z PATH.

Wyszukiwanie plików wykonywalnych w folderach na podstawie zmiennej PATH

Wyniki

Dzisiaj rozmawialiśmy o pętlach for i while w skryptach bash, o tym, jak je uruchamiać i jak nimi zarządzać. Teraz już wiesz jak przetwarzać w pętlach ciągi znaków z różnymi ogranicznikami, wiesz jak przekierowywać dane wyjściowe w pętlach do plików, jak przeglądać i analizować zawartość katalogów.

Jeśli założymy, że jesteś programistą skryptów basha, który wie o nich tylko to, co jest napisane w tej serii artykułów i w tym drugim, to możesz już napisać coś przydatnego. Przed nami trzecia część, po jej zrozumieniu dowiesz się, jak przekazywać parametry i przełączniki wiersza poleceń do skryptów basha i co z tym wszystkim zrobić.

Krótki opis różnic w typach pętli:

for - wykona akcję, dopóki istnieją obiekty do wykonania (na przykład odczytanie strumienia ze standardowego wejścia, pliku lub funkcji);
while - wykonuje akcję do stan jest prawdą;
dopóki - będzie wykonywane tak długo, jak stan nie stanie się prawdą, tj. na razie to nieprawda.

Pętla FOR

Rozważ tę wersję skryptu z pętlą:

$ cat pętli.sh #!/bin/bash dla zmiennej w `ls -1` wykonaj echo "$zmienna" zrobione

Składnia jest bardzo prosta i dość wyraźnie pokazana na przykładzie:

for (uruchamianie pętli) zmienna (deklaracja zmiennej, na której będziemy wykonywać akcje) w (wysyłanie przepływu do pętli) `ls -1` (polecenie do wykonania i przekazane do zmiennej $zmienna). Do i sporządzono to „treść” pętli, w obrębie której zostaną wykonane główne akcje na odebranych danych, a echo „$zmienna” to rzeczywista akcja wykonywana przez pętlę.

Zmieńmy teraz trochę przykład i zamiast jawnie określać polecenie, użyjemy drugiej zmiennej:

$ cat pętli.sh #!/bin/bash ls=`ls -1` dla zmiennej w $ls wykonaj echo "$zmienna" zrobione

Teraz polecenie ls -1 jest przekazywane w osobnej zmiennej, co pozwala na bardziej elastyczną pracę z pętlą. Zamiast zmiennej w pętli możesz także użyć funkcji:

$ cat pętli.sh #!/bin/bash lsl () ( ls -1 ) dla zmiennej w `lsl` wykonaj echo "$zmienna" zrobione

Głównym warunkiem pętli for jest to, że będzie ona wykonywana tak długo, jak przekazane jej polecenie zawiera obiekty do akcji. Bazując na powyższym przykładzie - o ile ls -1 ma pliki do wyświetlenia - pętla przekaże je do zmiennej i wykona „treść pętli”. Gdy tylko lista plików w katalogu się skończy, pętla zakończy swoje wykonanie.

Sprawmy, aby przykład był nieco bardziej skomplikowany.

Katalog zawiera listę plików:

$ ls -1 plik1 plik2 plik3 plik4 plik5 pętla.sh nofile1 nofile2 nofile3 nofile4 nofile5

Musimy spośród nich wybrać tylko te, które nie mają słowa „ NIE«:

$ cat pętli.sh #!/bin/bash lsl=`ls -1` dla zmiennej w $lsl wykonaj echo "$zmienna" | grep -v „nie” zrobione $ ./loop.sh plik1 plik2 plik3 plik4 plik5 pętla.sh

W pętli można także używać wyrażeń warunkowych ( wyrażenia warunkowe) […], aby sprawdzić warunki i instrukcję break, aby przerwać pętlę, jeśli warunek zostanie uruchomiony.

Rozważmy ten przykład:

$ cat pętli.sh #!/bin/bash lsl=`ls -1` dla zmiennej w $lsl wykonaj if [ $zmienna != "loop.sh" ] następnie echo "$zmienna" | grep -v „nie” w przeciwnym razie przerwanie fi zakończone

Pętla będzie kontynuowana aż do napotkania plikuloop.sh. Gdy tylko wykonanie pętli dotrze do tego pliku, pętla zostanie przerwana komendą break:

$ ./loop.sh plik1 plik2 plik3 plik4 plik5

Innym przykładem jest użycie operacji arytmetycznych bezpośrednio przed wykonaniem ciała pętli:

$ cat pętli.sh #!/bin/bash for ((liczba=1; liczba<11; count++)) do echo "$count" done

Tutaj ustawiamy trzy polecenia sterujące - liczba = 1, warunek kontrolny - gdy liczba jest mniejsza niż 11 i polecenie do wykonania - liczba +1:

Pętle WHILE i UNTIL

Prosty przykład, który wyraźnie pokazuje, jak działa pętla while:

$ cat pętli.sh #!/bin/bash liczba = 0 podczas [ $ liczba -lt 10 ] do ((liczba++)) echo $ liczba wykonana

Ustawiamy zmienną $count na zero, a następnie uruchamiamy pętlę whi z warunkiem „jeśli liczba $ jest mniejsza niż dziesięć, wykonaj pętlę”. W ciele pętli wykonujemy przyrost przyrostkowy+1 do zmiennej $count i wynik jest wypisywany na standardowe wyjście.

Wynik wykonania:

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

Gdy tylko wartość zmiennej $count osiągnęła 10, pętla zatrzymywała się.

Dobry przykład „nieskończonej” pętli, która pokazuje, jak działa while:

$ cat pętla.sh #!/bin/bash liczba = 10 podczas gdy [ 1 = 1 ] wykonaj ((liczba++)) echo $ liczba wykonana $ ./loop.sh ... 5378 5379 5380 5381 5382 5383 ^C

Pętla Until działa podobnie, ale w przeciwnym kierunku:

$ cat pętli.sh #!/bin/bash liczba = 0 do [ $ liczba -gt 10 ] do ((liczba++)) echo $ liczba zakończona

Tutaj ustawiamy podobny warunek, ale zamiast „kiedy zmienna jest mniejsza niż 10”, podajemy „aż zmienna stanie się większa niż 10”. Wynik wykonania:

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

Jeśli powyższy przykład „nieskończonej pętli” zostanie wykonany przy użyciu Until, nie wyświetli niczego, w przeciwieństwie do while:

$ cat pętli.sh #!/bin/bash liczba = 10 do [ 1 = 1 ] do ((liczba++)) echo $ liczba wykonana $ ./loop.sh $

Ponieważ " stan» pierwotnie « PRAWDA„-treść pętli nie zostanie wykonana.

Podobnie jak w pętli for, możesz używać funkcji in while i before. Na przykład pętla z rzeczywistego skryptu sprawdzającego status serwera Kocur(PID jest pobierany z systemu SLES, może się różnić w innych systemach), wersja nieco uproszczona:

$ cat pętli.sh #!/bin/bash check_tomcat_status () ( RUN=`ps aux | grep Tomcat | grep -v grep | grep java | awk "(drukuj $2)"` ) while check_tomcat_status wykonaj if [ -n "$ URUCHOM" ], a następnie printf "OSTRZEŻENIE: Tomcat nadal działa z PID $RUN."

Wynik wykonania:

else printf „Tomcat zatrzymany, kontynuuje… nn” przerwanie zakończone

$ ./loop.sh OSTRZEŻENIE: Tomcat nadal działa z PID 14435 26548. OSTRZEŻENIE: Tomcat nadal działa z PID 14435 26548. OSTRZEŻENIE: Tomcat nadal działa z PID 14435 26548. OSTRZEŻENIE: Tomcat nadal działa z PID 14435 26548. OSTRZEŻENIE: Tomcat nadal działa działa z PID 14435 26548. OSTRZEŻENIE: Tomcat nadal działa z PID 14435 26548. OSTRZEŻENIE: Tomcat nadal działa z PID 14435 26548. OSTRZEŻENIE: Tomcat nadal działa z PID 14435

Pełna wersja:

Check_tomcat_status () ( RUN=`ps aux | grep tomcat | grep -v grep | grep java | awk "(drukuj 2 $)"` ) while check_tomcat_status; wykonaj if [ -n "$RUN" ], a następnie printf "OSTRZEŻENIE: Tomcat nadal działa z PID $RUN. Zatrzymaj go? " odpowiedz "Zatrzymywanie Tomcat..." "Kontynuacja instalacji..." && $CATALINA_HOME/bin/shutdown .sh 2&>1 /dev/null || przerwać sen 2 if [ -n "$RUN" ] to printf "Tomcat nadal działa. Zabić go? " odpowiedź "Zabić Tomcat..." "Kontynuacja instalacji...n" && zabij $RUN || przerwać sen 2 fi else printf „Tomcat zatrzymany, kontynuuje… nn” przerwa fi zakończona

Funkcja odpowiedzi została opisana w artykule, ale tutaj zastosowano nieco ulepszoną wersję:

Odpowiedź () ( podczas czytania odpowiedzi; wykonaj echo case $odpowiedź w |) printf "1n $" return 0 break ;;

5

|) printf "2n $" zwróć 1 przerwę ;;

*) printf "Proszę wpisać T(tak) lub N(nie)!" esac gotowe )

Tutaj można było użyć zarówno while, jak i Until - ale nie pętli for, ponieważ for zadziałałoby raz (otrzymał PID i zakończył się).

1) Twój skrypt jest zakodowany w niebezpieczny sposób. Po pierwsze, zakładam, że używasz powłoki Bash, ponieważ oznaczyłeś ją znakami „/bash” i „/for”. W mojej odpowiedzi zacytuję ten znakomity przewodnik po języku Bash, który jest prawdopodobnie najlepszym źródłem do nauki języka Bash.

Mówiąc konkretnie, $(find$ DIRWORK -type d -name work) i $(find$ DIR -type f) zostaną poddane dzieleniu słów, zatem jeśli find znajdzie plik ze spacjami w nazwie, tj. „nazwa pliku”, wynik podziału słów Bash przekaże 2 argumenty do polecenia for w celu wykonania iteracji, tj. jeden dla „pliku” i jeden dla „nazwy”. W tym przypadku chcesz mieć nadzieję, że otrzymasz komunikaty „plik: brak takiego pliku lub katalogu” i „nazwa: nie ma takiego pliku lub katalogu”, zamiast potencjalnie je uszkodzić, jeśli faktycznie istnieją.

2) Zgodnie z konwencją zmienne środowiskowe (PATH, EDITOR, SHELL, ...) i wewnętrzne zmienne powłoki (BASH_VERSION, RANDOM, ...) są pisane wielką literą. Wszystkie pozostałe nazwy zmiennych muszą być pisane małymi literami. Ponieważ w nazwach zmiennych rozróżniana jest wielkość liter, konwencja ta pozwala uniknąć przypadkowego przesłaniania zmiennych środowiskowych i wewnętrznych.

To jest bezpieczniejsza wersja Twojego skryptu, której polecam zamiast tego użyć:

Mój_dom="/root/mydir" my_dir=" $mój_dom/var" dir_work="$ mój_dom/Lokalny" while IFS= read -r -d "" f; do # Zgaduję, że chcesz także zignorować stderr; # stąd pochodzi 2>&1. if lsof -n " ​​$f" | grep "" > /dev/null 2> to echo "hej , ja "Teraz jestem bezpieczniejszy!"< <(find "$ dir_work" -type f -print0) while IFS= read -r -d "" f; do echo "2" done < <(find "$dir_work" -type d -name "work" -print0)

gotowe

Jak widać, zmienna IFS jest ustawiona na pustą, co uniemożliwia odczytowi przycięcie przedniej i tylnej przestrzeni linii. Polecenie read używa pustej linii (-d "") jako ogranicznika do odczytu, aż dotrze do \0. find musi odpowiednio wynosić m, więc używa opcji -print0 do oddzielania danych za pomocą \0 zamiast znaku nowej linii, co oznacza , co zaskakujące i złośliwe, może być częścią nazwy pliku. Podzielenie takiego pliku \n na dwie części spowoduje uszkodzenie naszego kodu.

Poprzednia odpowiedź, w której stwierdzono, że znalezisko... | podczas czytania imienia; Do ...; Do odczytania wyników find s należy użyć polecenia „done”, które również może być złe. Pętla while działa w nowej podpowłoce z własną kopią zmiennych skopiowanych ze swojego rodzica. Ta kopia jest następnie używana do dowolnych celów. Po zakończeniu pętli while kopia podpowłoki zostanie odrzucona, a oryginalne zmienne rodzica nie zostaną zmodyfikowane.

0

„Nigdy nie używaj żadnego rodzaju podstawienia poleceń bez cudzysłowów.” To tylko czepianie się, ale możliwe jest użycie podstawienia poleceń bez cudzysłowów, gdy ustawiasz zmienną: „coś = $(nazwa podstawowa” nazwa pliku ze spacjami „)”. - Smith John 22 kwietnia 13 2013-04-22 21:43:10

2

Dla i w $(find$ DIRWORK -type d -name work); wykonaj echo „2” zrobione

będzie pierwszym, który wykona tę linię

Znajdź pracę $DIRWORK -type d -name

poczekaj, aż find zakończy wykonywanie, a następnie weź dzień wolny i włóż go z powrotem do pętli for

Dla i na wyjściu find; wykonaj echo „2” zrobione

dopiero wtedy rozpocznie się wykonywanie pętli for.

Jeśli więc zakończenie pętli for find zajmuje dużo czasu, musi poczekać dużo czasu, zanim będzie mogło się rozpocząć.

Wypróbuj interaktywne polecenia wyszukiwania tymczasowego

$ czas znajdź $DIRWORK -type d -name praca

i zobacz, ile czasu to zajmie.

Uwaga: nie powinieneś używać pętli for do iteracji po nazwach plików. Użyj pętli while z read w ten sposób:

Znajdź$ DIRWORK -typ d -nazwa praca | podczas czytania imienia; wykonaj echo „2” zrobione

Bonus: uruchamia pętlę while równolegle z find . Oznacza to, że pętla while zakończy jedną iterację, gdy tylko find wyświetli jedną linię. Nie ma potrzeby czekać na zakończenie wykonywania funkcji find.

W tym wykładzie kontynuujemy zapoznawanie się grzmotnąć. Przypominam, że rozważamy właśnie te elementy grzmotnąć, co pomoże nam zrozumieć skrypty systemu operacyjnego. Takimi elementami są z pewnością pętle i funkcje. Jeśli ktoś studiował programowanie, nie będzie miał trudności ze zrozumieniem tych pytań.

dla pętli

Cykl Do V grzmotnąć ma dwa typy. Przyjrzyjmy się najpierw wersji klasycznej Do. Ogólny pogląd jest następujący:

Pomiędzy elementami Do I W ustawiana jest zmienna, która z kolei przyjmuje wartość z ciągu wartości określonych pomiędzy W I Do. Między Do I zrobione istnieją polecenia, które są wykonywane za każdym razem, gdy zmienna zmienia swoją wartość. Pętla kończy się, gdy zmienna przyjmuje ostatnią wartość z sekwencji. Wartości w sekwencji oddzielane są spacjami.

Oto praktyczny przykład:

Sekwencję wartości można określić na różne sposoby. Jawnie - jak w powyższym przykładzie lub przy użyciu innych zmiennych lub przy użyciu specjalnych poleceń. Spójrzmy na kilka przykładów. Ponieważ wartości są podawane oddzielone spacjami, wartościami takimi może być dowolna zmienna zawierająca ciąg znaków ze spacjami:

Wynik będzie taki sam jak w pierwszym przykładzie.

Jeśli chcesz określić ciąg liczb, możesz użyć polecenia nast oraz mechanizm substytucyjny. Zespół nast zwraca na ekran ciąg wartości numerycznych. Składnia jest prosta i będzie jasna na podstawie poniższego przykładu:

Wynik:

Wróćmy do drugiego typu Do. Często w skryptach można spotkać tzw. wariant C Do, który jest używany w pętlach liczbowych. Rzućmy okiem na przykład:

Pętla działa tak długo, jak testowany warunek w wyrażeniu jest prawdziwy. Gdy tylko wyrażenie zwróci wartość false, wykonywanie pętli zostanie zatrzymane.

Praktyczny przykład:

#!/bin/bash
ja=1
podczas gdy [ $i -lt 7 ]
Do
echo $i
niech i=i+1
zrobione

W naszym przykładzie sprawdzamy, czy zmienna I jest mniejsza niż (-lt) liczba 7 i jeżeli tak, to na ekranie wyświetlana jest wartość zmiennej. Wyrażenie niech i=i+1, zwiększa zmienną o jeden, sprawdza ponownie itp. let mówi interpreterowi, że argumenty powinny być rozpoznawane jako wartości liczbowe. Linię tę można zapisać jako niech ja++(wariant podobny do c). Gdy liczba wzrasta o więcej niż jeden, można to zapisać w następujący sposób: niech ja+=2- w tym przypadku I będzie wzrastać w przyrostach co 2. Inną opcją zwiększania zmiennej jest użycie wbudowanego kalkulatora (działa tylko z liczbami całkowitymi). Dostęp do kalkulatora można uzyskać poprzez podwójne nawiasy: i=$(($i+1)) lub przez kwadratowe: i=$[$i+1] Możesz także użyć kalkulatora w wierszu poleceń:

Trzeba uważać z pętlami, żeby nie skończyć się pętlą nieskończoną. Przy okazji do debugowania grzmotnąć skrypty, na które możesz zmienić pierwszą linię #!/bin/bash -x lub uruchom skrypt za pomocą polecenia bash -x:

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

Pamiętaj, aby poćwiczyć pisanie małych skryptów, aby ugruntować swoją wiedzę na temat działania pętli grzmotnąć.

Funkcje w bashu

Funkcje są używane w grzmotnąć bardzo szeroki. Funkcje opisuje się na dwa sposoby: za pomocą słowa kluczowego funkcjonować i bez tego.

Pierwszy sposób:

funkcja nazwa_funkcji
{
ciało funkcyjne
}

Drugi sposób:

nazwa_funkcji()
{
ciało funkcyjne
}

Funkcja jest wywoływana po nazwie w dowolnym miejscu skryptu, ale dopiero po opisaniu samej funkcji. Do funkcji można również przekazywać parametry, które są oddzielane spacją po wywołaniu funkcji (nazwie). Spójrzmy na przykładowy skrypt grzmotnąć:

#!/bin/bash
podkład funkcyjny
{
jeśli [ $# -ne 0 ]
Następnie
lokalny a=1
echo "Liczba przekazanych parametrów - $#"
dla mnie w $@
Do
echo "$a-tym parametrem jest $i"
niech +
zrobione
zwróć 0
w przeciwnym razie
echo „Parametry nie zostały przekazane”
powrót 1
fi
}
echo „Wywołaj funkcję z parametrami:”
elementarz a b c
powtórzyć $?
echo „Wywołaj funkcję bez parametrów:”
elementarz
powtórzyć $?

W tym przykładzie funkcja o nazwie elementarz. Wywołanie funkcji z parametrami: elementarz a b c i bez parametrów: elementarz. W ciele funkcji wszystkie konstrukcje powinny być Ci znane, z wyjątkiem $# , $tj I $@ .$# — zwraca liczbę parametrów przekazanych do funkcji. W naszym przykładzie będzie to liczba 3 .$@ zwraca wszystkie parametry w jednej linii. W przykładzie tak a b c. I przez $1 , $2 , $3 itp. Dostęp do każdego parametru można uzyskać indywidualnie. $? — zawiera kod wykonania ostatniego polecenia. W naszym przykładzie kod wykonania funkcji.

Funkcja może również zwrócić wartość liczbową za pomocą słowa kluczowego powrót. Zwykle zwracają 0, jeśli funkcja została wykonana bez błędów, lub wartość różną od zera, jeśli coś poszło nie tak. W przykładzie, jeśli funkcja została wywołana z parametrami, zwracana jest wartość 0, a jeśli funkcja została wywołana bez parametrów, zwracany jest kod 1.

Wszystko, co dotyczy przekazywania parametrów do funkcji, działa dokładnie tak samo w przypadku skryptu. Możesz także przekazywać parametry do skryptu i manipulować nimi w ten sam sposób, używając $#, $@, $N. Z tej samej kategorii jest opcja - $0 - która zwraca nazwę polecenia, które uruchomiło skrypt. Jeśli skrypt został uruchomiony za pomocą polecenia ./script.sh, potem echo $0 zwróci wartość ./script.sh, a jeśli na polecenie /home/igor/linux/script.sh, wówczas wartość zostanie zwrócona /home/igor/linux/script.sh.

© 2024 ermake.ru - O naprawie komputerów PC - Portal informacyjny