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