Programowanie w
języku powłoki
Potoki, strumienie, przekierowania
2 Będziemy zajmować się programowaniem w powłoce sh (Bourne'a),
wspominając czasem o rozszerzeniach powłoki bash (Bourne Again
Shell).
Potoki przypominają budowanie z klocków. Możemy je składać:
ps -a | sort | uniq | grep -v sh | more
Przekierowania służą do zmiany przepływu informacji z i do
programów. Standardowe deskryptory to: 0 - wejście, 1 - wyjście, 2 - wyjście błędów. Przykłady:
ps -ax >> procesy.txt
find / -name qqq -print > findout.txt 2>finderr.txt kill -l 1234 > killouterr.txt 2>&1
Wybrane komendy:
grep
3 Służy do wyszukiwania zadanych wzorców w plikach
(szczegóły: man grep).
grep -l 'bzyk' kubus[12].* grep -r -i 'Kubus' ..
grep -i -n -v "\-bzyk*" kubus[12].* grep -C 2 -e '-bzyk' kubus*
grep 'dzien\>' kubus* ps -ef | grep '[c]ron' grep 'tomek' /etc/passwd
cat /etc/passwd | grep 'tomek' - /etc/shadow
4
Wybrane komendy:
find
Służy do wyszukiwania plików o określonych własnościach (szczegóły: man find).
Opcje
-atime n ostatnie żądanie dostępu do pliku miało miejsce
dokładnie n dni temu
-mtime n plik był modyfikowany dokładnie n dni temu
-newer nazwplik był modyfikowany później niż plik o nazwie nazw -size n rozmiar pliku wynosi dokładnie n bloków
-type c plik jest określonego typu: f -plik zwykły, d -katalog
itp.
-fstype typ typ systemu plików: ufs, 4.2, 4.3, nfs, tmp, ... -name wzorz nazwa pliku pasująca do wzorca wzorz
-perm p prawa dostępu do pliku ustawione na p -user usr plik, którego właścicielem jest usr
-group grp plik, którego grupą jest grp
-nouser właściciel pliku nie figuruje w pliku haseł -nogroup grupa pliku nie figuruje w pliku grup
5 Pow. opcje można używaæ z '
+
' i '-
' i znaczą więcej i mniej, np.:-mtime +7 pliki modyfikowane więcej niż 7 dni temu
-atime -2 pliki, do których ostatnie żądanie dostępu miało
miejsce mniej niż 2 dni temu
-size +100 pliki większe niż 50 Kb
-perm -002 pliki mające ustawiony najmniej drugi bit uprawnień,
czyli co najmniej prawo do pisania dla pozostałych
Koniunkcję
warunków uzyskujemy wypisując je jeden za drugim. Np.: pliki, do których nikt nie żądał dostępu od ponad dwóchmiesięcy i które od ponad czterech miesięcy nie były modyfikowane, to: -atime +60 -mtime +120
Alternatywę
uzyskujemy tak:\(-atime +30 -o -mtime +7\)
Negację
, natomiast tak:! -name g*.dat -name *.dat
6
jeszcze
Akcje
-print wyświetla nazwy znalezionych plików
-ls wyświetla pełniejszą informację o znalezionym pliku -exec cmd wykonanie na znalezionym pliku polecenia cmd
-ok cmd wykonanie na znalezionym pliku polecenia cmd z
żądaniem potwierdzenia
-xdev ograniczenie wyszukiwania tylko do systemu plików
zawierającego katalog początkowy
-prune zaniechanie wyszukiwania w znajdowanych katalogach
Zastosowanie
1. Testy zużycia miejsca na dysku
find /home -size +2048 -mtime +30 -exec ls -l {} \;
pliki większe od 1MB i niemodyfikowane od ponad miesiąca; a co to?:
find /home -size +2048 \
\( -mtime +30 -o -atime +120 \) \ -exec ls -l {} \;
7
i jeszcze
Wybrane komendy:
find
2. Odzyskiwanie miejsca na dysku:find / \( -name a.out -o -name core -o -name '*~' \ -o -name '.*~' -o -name '#*#' \) \
-type f -atime +14 \
-exec rm -f {} \; -o -fstype nfs -prune
3. Wyszukiwanie plików stanowiących zagrożenie dla systemu:
find / -type f \( -perm -2000 -o -perm -4000 \) \ -print | diff - files.secure
patrz także plik find1.sh
4. Wykonywanie powtarzających się czynności:
find /home/tomek -exec chown tomek {} \; \
-exec chgrp informatyka {} \;
find . -depth -name '*.txt' ! -name 'f*' -print0 | \ tar --create --null --files-from=- -file=txty.tar
8
Wybrane komendy:
awk
Nazwa AWK pochodzi od nazwisk autorów: A.V.Aho,
P.J.Weinbergera i W.Kernighana. Jest językiem interpretowanym i nadaje się do przetwarzania logów tekstowych.
Zasada działania: wczytujemy rekord i dla niego wykonujemy wszystkie instrukcje. Potem następny, itd...
Programy składają się z bloków. Typowy blok wygląda nastąpująco:
<warunek> { <polecenia> }
Typowe warunki
i==5 oczywiste (składnia jak w C)
/a*bc/ akceptuje rekordy zawierające dowolną ilość liter a, a po
nich bc
BEGIN warunek prawdziwy zanim zostanie wczytany jakikolwiek
rekord
9
Wybrane komendy:
awk
zmienne
Nie deklarujemy zmiennych. Inicjalizacja następuje w momencie użycia wartością 0 lub "" (pusty ciąg znaków).Przykład:
x=5; x=2*x+yTablice są indeksowane napisami (tzw. tablice asocjacyjne).
Odwołanie przez liczbę powoduje zamianę liczby na odp. napis i dalej jak z napisem.
Przykład:
t["ala"]=2; t[2]=5Prócz operatorów z C, występuje operator ~ i oznacza zawiera
wyrażenie. Np.: "aaa"~/a/ jest prawdziwe, lecz "bbb"~/a/ nie
jest.Innym operatorem jest in i służy do sprawdzania czy dany element jest indeksem tablicy. Np: "ala" in t. Warunki takie mogą
występować w programach (skadnia jak w C - patrz man awk):
wart="ala"
10
Wybrane komendy:
awk
zmienne cd
$0 wczytany rekord
$1,... kolejne pola we wczytanym rekordzie
$x pole we wczytanym rekordzie o numerze takim jak
wartość zmiennej x
NF liczba wczytanych pól
FS separator pól, wpisujemy wyrażenie regularne
opisujące separatory, domyślny: spacja
Itd...
Wywołania
awk -f <plik_z_programem> <plik_wej1> <plik_wej2>... #!/bin/awk -f
11
Wybrane komendy:
awk
przykłady
(date; ps -ef | grep [d]oom | \
awk '{print $1 " [" $7 "]" }' | \
sort | uniq) >> doomed.users awk1.sh
find /home -user $1 -fstype ext3 -ls | awk \
'{sum+=$7}; END {print "Total disk use = " sum}' awk2.sh #!/usr/bin/awk -f { for (i = 1; i <= NF; i++) freq[$i]++ } END {
for (word in freq)
printf "%s\t%d\n", word, freq[word] }
Zmienne środowiska:
sh
Powłoki posiadają predefiniowane zmienne środowiskowe. Mogą one być modyfikowane przez użytkownika. Np.:
$HOME katalog macierzysty obecnego użytkownika
$PATH podzielona znakami ":" lista katalogów przeszukiwanych
przez polecenia
$PS1 znak zgłoszenia systemu, przeważnie $
$PS2 dodatkowy znak zgłoszenia systemu, przeważnie >
$IFS separator pól wejściowych; lista znaków używanych do
rozdzielania param. wejściowych czytanych przez powłokę
$0 nazwa wykonywanego skryptu
$1,... parametry przekazane do skryptu $# liczba przekazanych parametrów
$$ PID procesu wykonywanego skryptu; często używany
wewnątrz skryptu do tworzenia niepowtarzalnych nazw
$* lista wszystkich paramertów porozdzielanych pierwszym
znakiem zmiennej $IFS
Deklaracja zmiennych
Składnia:
13
declare [-afFirx] [-p] [zmienna[=warto??]]
Polecenie to deklaruje zmienną i ewentualnie nadaje jej wartość. Znaczenie poszczególnych opcji (patrz także man bash):
-a definiowana zmienna jest tablicą -f definiowana zmienna jest funkcją
-F jak -f z tym, że definiowana funkcja nie jest wyświetlana
-i definiowana zmienna jest zmienna całkowitą
-r definiowana zmienna jest przeznaczona tylko do odczytu -x definiowana zmienna jest przeznaczona do eksportu przez
środowisko
-p wyświetla zmienną wraz z jej definicją
Polecenie
test
czyli
[ ]
14 Polecenie to służy do testowania warunków. Np.: test -f plik
sprawdza czy istnieje plik o nazwie plik równoważne [ -f plik ]
Testy
-d plik czy plik jest katalogiem -e plik czy plik istnieje
-f plik czy plik jest plikiem reg. -g plik czy plik posiada GUID
-u plik czy plik posiada SUID -r plik czy plik daje się czytać
-s plik czy plik ma niezerowy rozm. -w plik czy do pliku można pisać
-x plik czy plik jest wykonywalny
Porównania
e1 -eq e2 czy e1 = e2 e1 -ne e2 czy e1!= e2 e1 -gt e2 czy e1 > e2 e1 -ge e2 czy e1 >=e2 e1 -lt e2 czy e1 < e2 e1 -le e2 czy e1 <=e2
!
e1 negacja e1UWAGA
1. W historii UNIXa -e bylo nieprzenośne i raczej używa się -f.
Instrukcje sterujące
15if-then-else
if warunek then instrukcje else instrukcje fi if1.sh i if2.shfor-in- do-done
for zmienna in warto?ci do instrukcje done for1.sh i for2.sh
while-do-done
while warunek do instrukcje done while1.sh i while2.sh until1.sh i until2.shcase-in-esac
case zmienna inwzorzec [| wzorzec ...]) instr;; wzorzec [| wzorzec ...]) instr;; ...
Listy AND i OR
16
Lista AND umożliwia wykonanie serii poleceń. Kolejne polecenie jest
wykonane, gdy poprzednie zakończy się sukcesem. Cała lista kończy się sukcesem, gdy wszystkie polecenia zakończą się sukcesem.instr1 && instr2 && ... && instrn and1.sh
Lista OR umożliwia wykonanie serii poleceń, aż jedno zakończy się
sukcesem, wtedy żadne już nie będą wykonywane.Wykonanie następuje od lewej do prawej (podobnie jak w liście AND).
instr1 || instr2 || ... || instrn or1.sh
Pytanie
Jakie jest wiązanie operatorów list? Czyli, jak działają listy mieszane?
Funkcje
17 nazwa_funkcji () { instrukcje }Składnia
Funkcja może oddawać wartość liczbową, używając polecenia:
return warto??
Ciągi znaków mogą być przekazywane jedynie przez zmienne globalne
W funkcjach można używać zmiennych lokalnych
Przykłady
1. Prosta funkcja fun1.sh
2. Zmienne lokalne funkcji fun2.sh
3. Funkcja zwracająca wartość fun3.sh
4. Przekazywanie wartości do funkcji fun4.sh
5. Funkcje robiące coś fun5.sh
Tablice
18 W bashu dostępne są jednowymiarowe tablice. Deklaruje się je za
pomocą plecenia declare -a lub niejawnie przez wystąpienie wyr. nazwa[indeks]=warto??, gdzie indeks jest wyr. arytm. > 0.
Tablice są indeksowane od 0. Można im nadawać wartości w sposób tradycyjny:
nazwa[indeks]=warto??
lub w bardziej złożony:
nazwa=(wart_1, ..., wart_n)
gdzie wart_i jest postaci [indeks_i]=string_i
Dowolny element tablicy może być odczytany za pomocą wyrażenia:
${nazwa[indeks]}
${nazwa[@]} rozwinie się do listy elementów tablicy
rozdzielonych pierwszym elementem zmiennej IFS ${nazwa[*]} jw. lecz wynik jest jednym ciągiem znaków
${#nazwa[idx]} długość ${nazwa[idx]}
Rozwijanie parametrów
19 Język powłoki udostępnia również mechamizmy: rozwijania
parametrów, dopasowywania wzorca, itp. (patrz man bash). ${par:-wyr} jeżeli par jest pusty, to wynikiem jest wyr, w
przeciwnym przypadku par
${par:=wyr} jeżeli par jest pusty, to jego wartością staje się wyr, następnie wynikiem jest par
${par:+wyr} jeżeli par jest pusty, to brak wyniku, w przeciwnym
przypadku wynikiem jest wyr
${par:off:len} wynikiem jest len znaków ciągu par zaczynając
od znaku off, jeżeli brak parametru len, wynikiem jest ciąg
znaków od off do końca par
${!prefix*} wynikiem jest lista nazw zmiennych zaczynających
się od prefix
${#par} wynikiem jest liczba znaków par, jeżeli par jest * lub @,
wynik to liczba przekazanych parametrów lub jeżeli par jest
Rozwijanie parametrów
20
${par#wyr} wyr opisuje wzorzec, wynikiem jest reszta pozostała
po najmniejszym dopasowaniu wzorca do par zaczynając od
początku par
cd
${par##wyr} jw. z tym, że następuje największe dopasowanie
wzorca; patrz parametry1.sh
${par%wyr} i ${par%%wyr} jak ${par#wyr} i ${par##wyr} z
tym, że następuje dopasowanie wzorca do końca par;
patrz parametry2.sh
${par/wyr/str} i ${par//wyr/str} wynikiem jest par, w
którym pierwsze największe dopasowanie wzorca wyr
zamieniono na str; w drugim przypadku zamienione zostaną
wszystkie dopasowania wzorca; wyr rozpoczynające się od #
oznacza dopasowanie do początku par; natomiast %, do
Polecenia
source
i
exit
21
source skrypt
Zwykle skrypt wykonuje się w podpowłoce powłoki wywołującej, tj. w jej nowym środowisku. Po zakończeniu skryptu, środowisko to jest usuwane i do środowiska macierzystego przekazywany jest tylko kod wyjścia skryptu. Zastosowanie polecenia source skrypt lub
. skrypt, spowoduje wykonanie skryptu w powłoce wywołującej. sou1.sh i sou2.sh
exit n
Polecenie to powoduje zakończenie skryptu z kodem wyjścia n.
Jeżeli nie użyjesz exit do zakończenia skryptu, to kod wyjścia
skryptu będzie kodem wyjścia ostatnio wykonywanego polecenia.
0 sukces
1-125 kody zdefiniowane przez użytkownika 126 plik nie był wykonywany
127 polecenie nie zostało znalezione
Polecenie
trap
22
trap [-l] polecenie sygna?
Jest stosowane do określania działań podejmowanych po otrzymaniu sygnału. trap -l wypisuje nazwy dostępnych sygnałów wraz z ich
wartościami liczbowymi. Polecenie trap powinno być wykonane
przed częścią kodu, którą chcemy chronić.
Sygnały
HUP (1) zawieszenie; wysyłany, gdy terminal zostaje wyłączony
lub użytkownik się wyloguje
INT (2) przerwanie; np. naciśnięcie Ctrl-C QUIT(3) wyjście; np. naciśnięcie Ctrl-\
ABRT(6) przerwanie; wysyłany po poważnym błędzie w trakcie
wykonywania
ALRM(14)alarm; obsługa przekroczenia dopuszczalnego czasu
TERM(15)zakończenie; wysyłany np. podczas zamykania systemu trp1.sh
Przykłady skryptów
23 Do jednych z ważniejszych zadań administratora systemu należy
zabezpieczenie systemu przed niepowołanym dostępem oraz dbanie o zasoby systemowe (np. zasoby dyskowe). Poniższe przykłady
pokazują w jaki sposób możemy zautomatyzować oba te zadania, używając skryptów powłoki.
Przykład 1
- skrypt ckpwd.shSkrypt ten sprawdza poprawność wpisów w pliku /etc/passwd,
oraz: czy istnieją konta bez haseł, czy istnieją inni użytkownicy niż root, którzy mają UID=GID=0, jakie konta zostały ostatnio dodane / usunięte i czy plik haseł posiada odpowiednie prawa dostępu.
Przykład 2
- skrypty ckdsk.sh i cmp_size.shSkrypty te pozwalają śledzić zmiany w wykorzystaniu przestrzeni dyskowej przez użytkowników.
Oba przykłady prezentują skrypty, które administrator powinien wykonywać często, przez cały czas życia systemu, to też można