pdf - Środowisko programisty
Transkrypt
pdf - Środowisko programisty
Środowisko programisty Zestaw 7 Semestr zimowy 2016/2017 Kraków, 10,15,16 listopad 2016 Bash, zmienne i instrukcje warunkowe Zmienne możemy traktować jak etykiety, które przechowują ciągi znaków. Definiujemy je przy pomocy znaku = bez spacji po obu jego stronach: dog="Azor" Do zmiennych w poleceniach odwołujemy się poprzedzając je symbolem $. Okazuje się, że to, czy nazwę zmiennej umieścimy pomiędzy apostrofami, czy też cudzysłowami, ma znaczenie – cudzysłów umożliwia specjalną interpretację znaku $. echo $dog −→Azor echo $dogek −→ echo ${dog}ek −→Azorek echo ’Jestem $LOGNAME, a to jest pies $dog.’ −→Jestem $LOGNAME, a to jest pies $dog. echo "Jestem $LOGNAME, a to jest pies $dog." −→Jestem boraks, a to jest pies Azor. Powyżej pojawiła się, zawierająca nazwę użytkownika, zmienna LOGNAME – jedna ze zmiennych środowiskowych. Są to zmienne, których zawartość jest dostępna dla wszystkich procesów uruchomionych w powłoce. Ich nazwy zapisujemy dużymi literami. Przykłady innych zmiennych środowiskowych: HOSTNAME nazwa (adres) maszyny, na którą się zalogowaliśmy, HOME ścieżka do katalogu domowego użytkownika, PATH ścieżki (oddzielone dwukropkami), w których szukane są programy powłoki, PWD ścieżka do aktualnego katalogu. Wszystkie zmienne środowiskowe możemy wypisać komendą env (choć nie jest to jej główne przeznaczenie – patrz man env). W praktyce opłaca się nam często zmodyfikować zmienną PATH w pliku ~/.bashrc w celu szybkiego uruchamiania naszych programów (skryptów) z danego katalogu: PATH=$PATH:$HOME/scripts Jeżeli w katalogu scripts znajdował się program o nazwie cmd, to od tej pory będziemy go mogli uruchomić w dowolnym miejscu wpisując po prostu cmd. Z poprzednich notatek wiemy, że do nazwy skryptu możemy się dostać za pomocą: "$0". Natomiast do kolejnych argumentów przekazanych do skryptu za pomocą: "$1", "$2", "$3", itd., itp. Do listy parametrów możemy dostać się za pomocą $@, do liczby parametrów za pomocą: $#. Strona 1/9 Środowisko programisty Zestaw 7 Semestr zimowy 2016/2017 Kraków, 10,15,16 listopad 2016 Wyrażenia regularne oraz glob patterns w bashu Bash używa rozszerzonych wyrażeń regularnych, czyli extended regular expressions (ERE), z którymi mamy do czynienia np. uruchamiając grepa z flagą -E Glob patterns (w skrócie globy) to wzorce (wyrażenia) w bashu, które dopasowują się do nazw plików lub innych ciągów snaków. Szczególnie przydatne są w pierwszym przypadku. Podobnie jak w przypadku omawianych wcześniej wyrażeń regularnych, Globy oprócz zwykłych znaków używają również specjalnych meta-znaków. Są to: * dopasowuje się do dowolnego ciągu znaków włączając w to słowo puste ? dopasowuje się do dowolnego pojedynczego znaku [...] dopasowuje się do dowolnego znaku w nawiasach kwadratowych Globy w przeciwieństwie do wyrażeń regularnych omawianych wcześniej są domyślnie "zakotwiczone z obu stron". W szczególności a* nie dopasuje się do ciągu: katastrofa. Dopasuje się natomiast do: aerobik. Natomiast ka* dopasuje się do słowa katastrofa. Globa *.c można wykorzystać np. do wypisania wszystkich plików żródłowych w C w danym katalogu. Używamy do tego komendy echo: echo *.c. W przypadku, kiedy glob jest używany do dopasowywania nazw plików ani *, ani ? nie dopasowują się do slasha (/). Testowanie warunków logicznych w bashu Polecenie test warunek_1 operator warunek2 sprawdza wartość wyrażenia. Polecenie test może być zapisane za pomocą nawiasów kwadratowych, które tak naprawdę są aliasem do tego polecenia: [ wyrażenie1 operator wyrażenie2 ] Należy pamiętać, że po [ oraz przed ] spacja jest wymagana. Uwaga ta dotyczy również podwójnych nawiasów kwadratowych [[ ]] omawianych poniżej. Operacje arytmetyczne: -eq -ne -lt -le -gt -ge równy różny mniejszy niż mniejszy lub równy większe niż większe lub równy Operacje na stringach: Strona 2/9 Środowisko programisty Zestaw 7 Semestr zimowy 2016/2017 Kraków, 10,15,16 listopad 2016 = != < > -n -z równy różny pierwszy string alfabetycznie przed drugim pierwszy string alfabetycznie za drugim string ma długość większą niż 0 string ma zerową długość Przykładowe operacje na plikach: -e PLIK -s PLIK -d PLIK -r PLIK PLIK1 -nt zwraca zwraca zwraca zwraca PLIK2 zwraca true true true true true jeśli jeśli jeśli jeśli jeśli PLIK isntieje PLIK isntieje i jest niepusty PLIK jest katalogiem użytkownik ma prawo do czytania PLIK1 jest nowszy niż PLIK2 Łączenie wyrażeń odbywa się przez alternatywę || lub koniunkcję &&: warunek1 || warunek2 || warunek3 ... warunek1 && warunek2 && warunek3 ... Wyrażenia są sprawdzane po kolei, aż do momentu kiedy da się już określić wartość logiczną całego wyrażenia. Dlatego alternatywa wykonuje się do momentu gdy jakieś wyrażenie zwróci TRUE albo do końca i jeśli wszystkie wyrażenia dadzą FALSE to cała alternatywa też będzie fałszywa. Natomiast koniunkcja odwrotnie, przerywana jest w momencie gdy jakieś wyrażenie zwróci FALSE, a jeśli nie to wykonuje się do końca i jeśli wszystkie wyrażenia dadzą TRUE to koniunkcja będzie prawdziwa. Obok komendy [ ] bash oferuje komendę [[ ]], która daje więcej możliwości. W szczególności w podwójnych kwadratowych nawiasach możemy umieścić następujące warunki: [[ NAPIS = (lub ==) GLOB ]] zwraca true, jeśli NAPIS dopasowuje się do globa GLOB [[ NAPIS != GLOB ]] zwraca false, jeśli NAPIS NIE dopasowuje się do globa GLOB [[ NAPIS =~ REGEX ]] zwraca true, jeśli NAPIS dopasowuje się do wyr. reg. REGEX Instrukcje sterujące W bash-u występują dwie instrukcje warunkowe if then else oraz case. Przyjrzyjmy się ich składni. if [ warunek ] ; then polecenia elif [ warunek ] ; then polecenia else polecania Strona 3/9 Środowisko programisty Zestaw 7 Semestr zimowy 2016/2017 Kraków, 10,15,16 listopad 2016 fi Instrukcja else jest opcjonalna i nie musi być używana. To samo dotyczy elif, która zastępuje else if (warunek), jak to piszemy używając np. C,C++. Instrukcja if musi być zakończona przez fi. Przykład sprawdzający pierwszy czy argument skryptu jest równa zeru: #!/bin/bash if [ $1 -eq 0 ] ; then echo "$1 jest równe zeru" else echo "$1 jest różne od zera" fi W instrukcji warunkowej zamiast pojedynczych ([]) możemy użyć również podwójnych nawiasów kwadratowych [[]]. Pierwszy przykład pokazuje jak w tym kontekście używać globów a drugi jak wyrażeń regularnych. filename="somefile.jpg" if [[ $filename = *.jpg ]]; then echo "$filename is a jpeg" fi W powyższym przykładzie sprawdziliśmy, czy plik ma rozszerzenie jpg. W kolejnym sprawdzamy, czy pierwszy argument podany do skryptu jest liczbą. liczba=^[1-9][0-9]*$ if [[ $1 =~ $liczba ]]; then echo "$1 jest liczbą" fi Gdy musimy dla kolejnych wartości zmiennej wykonywać różne akcje, instrukcja if staje się niewygodna w użyciu. Do takich rozwiązań służy instrukcja case o następującej składni: case zmienna in "wzorzec") polecenie ;; "wzorzec") polecenie ;; "wzorzec") polecenie ;; *) polecenie wykonywane domyślnie esac Strona 4/9 Środowisko programisty Zestaw 7 Semestr zimowy 2016/2017 Kraków, 10,15,16 listopad 2016 W instrukcji case ilość wzorców może być dowolna. Przykład wypisujący odpowiednią informację zależną od pierwszego argumentu programu: #!/bin/bash case $1 in "0") echo "Jest OK" ;; "1") echo "Jest lepiej" ;; "2") echo "Jest jeszcze lepiej" ;; "3") echo "Jest super" ;; *) echo "Przesadzasz!" esac W bash-u istnieją kilka rodzajów pętli: for, while, until oraz select. Omówimy tutaj pierwsze trzy z nich. Pętla while wykonuje swoje działanie dopóki warunek jest spełniony: while [ warunek ] ; do polecenie done Przykład użycia, wypisanie 10 razy zmiennej i: #!/bin/bash i=1; while [ $i -le 10 ] ; do echo "$i" i=$[i + 1] done Pętla until różni się od poprzedniej tym że kończy swoje działanie w momencie gdy warunek stanie się prawdziwy: until [ warunek ] ; do polecenie done Przykład użycia, wypisanie 10 razy zmiennej i: #!/bin/bash i=0 until [ $i -ge 10 ] ; do echo "$i" i=$[i + 1] done Strona 5/9 Środowisko programisty Zestaw 7 Semestr zimowy 2016/2017 Kraków, 10,15,16 listopad 2016 Pętla for jest najciekawsza z bash-owych pętli, ponieważ może być używana na dwa sposoby. Po pierwsze możemy jej używać tak jak w C\C++, kiedy znamy ograniczenie na ilość iteracji: for ((inicjalizacja zmiennej; warunek zakończenia; zmiana zmiennej)) ; do polecenia done Przykład, wypisanie 10 razy wartości zmiennej i: #!/bin/bash for (( i=1; $i <= 10; i++ )) ; do echo " Iteracja nr: $i" done Drugie to iterowanie się po pewnej liście zbiorze elementów: for zmienna in lista ; do polecenia done Przykład, wypisanie wszystkich małych liter alfabetu angielskiego: for i in {a..z} ; do echo $i done Przykład, wypisanie nazw wszystkich plików z rozszerzeniem txt w bieżącym katalogu: for i in *.txt ; do echo $i done Aby przerwać działanie pętli uzywamy komendy break. Natomiast aby przeskoczyć do kolejnej iteracji służy polecenie continue. Strona 6/9 Środowisko programisty Zestaw 7 Semestr zimowy 2016/2017 Kraków, 10,15,16 listopad 2016 Tablice Poniżej przedstawiamy kilka sposobów na tworzenie tablic. Pierwszy przykład tworzy tablicę taką, że: names[0] = "Bob", names[1] = "Peter", itd. Tak, tablice numerujemy od zera. names=("Bob" "Peter" "$USER" "Big Bad John") Możemy również podać konkretne indeksy do których chcemy przypisać wartości. names=([0]="Bob" [1]="Peter" [20]="$USER" [21]="Big Bad John") W przypadku, kiedy chcemy wypełnić tablicę nazwami plików, rekomenduje się użycie globów. photos=(~/"My Photos"/*.jpg) W następnych przykładach używamy tablic z pętlą for. Używamy do tego konstrukcji: ${tablica[@]}, która tworzy listę zawierającą elementy tablicy. Pierwsze dwa przykłady dają ten sam efekt. names=("Bob" "Peter" "$USER" "Big Bad John") for name in "${names[@]}"; do echo "$name"; done for name in "Bob" "Peter" "$USER" "Big Bad John"; do echo "$name"; done Kolejny przykład operuje na nazwach plików, które możemy wczytać do tablicy za pomocą globa. for file in "${myfiles[@]}"; do cp "$file" /backups/ done Do liczby elementów w tablicy możemy dostać się za pomocą: ${#array[@]}. Natomiast ${!arrayname[@]} zwraca listę indeksów. Strona 7/9 Środowisko programisty Zestaw 7 Semestr zimowy 2016/2017 Kraków, 10,15,16 listopad 2016 Wczytywanie danych ze standardowego wejścia Prostą komendą czytającą pojedynczą linię wejścia jest read -opcje nazwa_zmiennej_do_której_czytamy. Przykład, wczytywanie napisów i łączenie ich w jeden: #!/bin/bash while read zmienna do napis=$napis" "$zmienna done echo $napis Aby czytać i zapisywać do pliku możemy użyć przekierowania: <, >. W poniższym przykładzie czytamy z pliku: plik.in i zapisujemy do pliku: plik.out #!/bin/bash while read zmienna do napis=$napis" "$zmienna done < plik.in echo $napis > plik.out Ewaluacja wyrażeń arytmetycznych w bashu Istnieje wiele sposobów na wyliczanie wartości wyrażenia w bash-u. Zwykłe wpisanie ich w instrukcji echo jednak nie wystarczy. Umieszczenie wyrażenia pomiędzy nawiasami: $((wyrażenie)) wykona je, ale jest ograniczone tylko do liczb całkowitych. echo "2+2" 2+2 echo $((7+7)) 14 Aby wykonać wyrażenia zmiennoprzecinkowe używamy polecenia bc -l: echo "2+2"| bc 4 Strona 8/9 Środowisko programisty Zestaw 7 Semestr zimowy 2016/2017 Kraków, 10,15,16 listopad 2016 echo "3+5.5"| bc -l 8.5 echo "2/5"| bc 0 echo "2/5"| bc -l .40000000000000000000 Używając parametru scale możemy określić liczbę liczb po przecinku, nie musimy wtedy używać -l. Należy jednak pamiętać, że ważna jest kolejność wyrażeń! echo "scale = 4; 11 * 110 / 70" | bc 17.2857 echo "scale = 4; 11 / 70 * 110" | bc 17.2810 echo "scale = 4; (11 / 70) * 110" | bc 17.2810 Strona 9/9