par
Transkrypt
par
Programowanie w języku powłoki Tomasz Borzyszkowski Potoki, strumienie, przekierowania 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 kill -l 1234 > /dev/null 2>&1 2 Wybrane komendy: grep 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 find ~ -name '*.c' -print | xargs grep -l 'hello' 3 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ł 4 -nogroup grupa pliku nie figuruje w pliku grup Wybrane komendy: find cd 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óch miesię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 5 Wybrane komendy: find jeszcze Akcje -print -ls -exec cmd -ok cmd -xdev -prune wyświetla nazwy znalezionych plików wyświetla pełniejszą informację o znalezionym pliku wykonanie na znalezionym pliku polecenia cmd wykonanie na znalezionym pliku polecenia cmd z żądaniem potwierdzenia ograniczenie wyszukiwania tylko do systemu plików zawierającego katalog początkowy 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 \) \ 6 -exec ls -l {} \; Wybrane komendy: find i jeszcze 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 7 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 warunek prawdziwy zanim zostanie wczytany jakikolwiek rekord warunek prawdziwy po wczytaniu ostatniego rekordu BEGIN END 8 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+y Tablice 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]=5 Pró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" if(wart in t) print t[wart] 9 Wybrane komendy: awk zmienne cd $0 wczytany rekord $1,... $x kolejne pola we wczytanym rekordzie pole we wczytanym rekordzie o numerze takim jak wartość zmiennej x liczba wczytanych pól separator pól, wpisujemy wyrażenie regularne opisujące separatory, domyślny: spacja NF FS Itd...... Wywołania awk -f <plik_z_programem> <plik_wej1> <plik_wej2>... #!/bin/awk -f awk '{print$1}' <plik1> ... 10 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] } awk3 11 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 Patrz skrypt zmienne.sh 12 Deklaracja zmiennych Składnia: 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ą Patrz skrypt decl.sh 13 Polecenie test czyli [ ] 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 -e -f -g -u -r -s -w -x plik plik plik plik plik plik plik plik plik czy czy czy czy czy czy czy czy czy Porównania plik jest katalogiem e1 -eq plik istnieje e1 -ne plik jest plikiem reg. e1 -gt plik posiada GUID e1 -ge plik posiada SUID e1 -lt plik daje się czytać e1 -le plik ma niezerowy rozm.! e1 do pliku można pisać plik jest wykonywalny e2 e2 e2 e2 e2 e2 czy e1 = e2 czy e1!= e2 czy e1 > e2 czy e1 >=e2 czy e1 < e2 czy e1 <=e2 negacja e1 UWAGA 1. W historii UNIXa -e bylo nieprzenośne i raczej używa się -f. 2. Własności SUID i GUID nie działają na skrypty powłoki. 14 Instrukcje sterujące if-then-else for-in- do-done if warunek then instrukcje else instrukcje fi if1.sh i if2.sh for zmienna in warto?ci do instrukcje done while-do-done case-in-esac for1.sh i for2.sh case zmienna in while warunek wzorzec [| wzorzec ...]) instr;; do wzorzec [| wzorzec ...]) instr;; instrukcje ... done case1.sh while1.sh i while2.shesac until1.sh i until2.sh 15 Listy AND i OR 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? instr1 && instr2 || instr3 16 Funkcje Składnia nazwa_funkcji () { instrukcje } 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 2. Zmienne lokalne funkcji fun1.sh fun2.sh 3. Funkcja zwracająca wartość fun3.sh 4. Przekazywanie wartości do funkcji fun4.sh 5. Funkcje robiące coś fun5.sh 6. Funkcja rekursywna hanoi.bash 17 Tablice 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]} Patrz array-stuff i array-to-string 18 Rozwijanie parametrów 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 tablicą z indeksem * lub @, wynikiem jest jej długość 19 Rozwijanie parametrów cd ${par#wyr} wyr opisuje wzorzec, wynikiem jest reszta pozostała po najmniejszym dopasowaniu wzorca do par zaczynając od początku par ${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 końca par patrz parametry3.sh 20 Polecenia source i exit 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 >127 pojawił się sygnał nr, gdzie nr+127 = kod wyjścia 21 Polecenie trap 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 22 Przykłady skryptów 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.sh Skrypt 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.sh Skrypty 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 zautomatyzować... 23