Co to jest BASH Kurs BASH

Bash to powloka systemowa UNIX napisana dla projektu GNU. Nazwa jest akronimem od Bourne-Again Shell (ang. znowu shell Bourne'a). Jest to jedna z najpopularniejszych powlok systemów uniksowych. Wywodzi sie od powloki Bourne'a sh, która byla jedna z pierwszych i najwazniejszych powlok systemu UNIX, i zawiera pomysly zawarte w powlokach Korna i csh. Pierwotna powloka Bourne'a byla tworzona przez Stephena Bourne'a. Bash byl pisany glównie przez Briana Foxa i Cheta Rameya. Powloka Bournea sh zostala stworzona okolo roku 1977. Powloka bash zostala napisana w roku 1987 przez Briana Foxa. W roku 1990 jej glównym opiekunem zostal Chet Ramey. Bash jest domyslna powloka w wiekszosci dystrybucji systemu Linux oraz w systemie Mac OS X w wersji 10.4 Tiger. Istnieja takze wersje dla wiekszosci systemów Unixowych. Bash jest takze domyslna powloka w srodowisku Cygwin dla systemów Win32. Program jest rozprowadzany na licencji GPL. Bash jest bardzo dobrym jezykiem skryptowym, sluzacym do efektywnego zarzadzania systemem.
Skrypt to nic innego jak zwykly jawny nie skompilowany plik tekstowy zawierajacy rózne instrukcje, polecenia systemowe, do wykonania przez zdefiniowany w skrypcie interpreter powloki systemowej (/bin/bash). Zadaniem powloki jest przetlumaczenie ich na polecenia systemu. Jesli ktos mial do czynienia z plikami wsadowymi (Batch) w systemie DOS to wlasnie skrypty sa tego typu plikami.

Kurs BASH
Spis Tresci
Hello World i wykonanie skryptu

Tradycyjnie pierwszym krokiem do pisania wlasnego kodu jest wyswietlenie na standardowym wyjsciu (stdout), tutaj ekran monitora, oslawionego tekstu "Hello World".
Zakladajac ze pracujemy np. w Linuksowej konsoli, w której mamy za powloke obrana wlasnie powloke bash wystarczy wydac komende:
echo "Hello World" 

Na wyjsciu dostaniemy w odpowiedzi napis Hello World. Dlaczego tak sie dzieje? Otóz pracujac w powloce bash od razu jestesmy w srodowisku w którym wykonujemy kod - powloka interpretuje bezposrednio polecenia dla niej zrozumiale i natychmiast podaje nam wynik dzialania instrukcji na nasz ekran. A teraz do rzeczy. Napiszmy prosty skrypt który wlasnie wydrukuje nam na nasz ekran monitora nasze Hello World.

Kazdy skrypt powinien zawierac na poczatku zdefiniowany rodzaj shella w jakim skrypt ma byc wykonany:
#!/bin/bash lub krócej #!/bin/sh 

tutaj skrypt zawsze bedzie wykonywany przez interpreter polecen bash, niezaleznie od tego jakiej powloki w danej chwili uzywamy. Przykladowo pracujemy w powloce csh, skrypt na czas wykonania zawartego w nim kodu wywola powloke bash:
tworzymy plik tekstowy o nazwie hello.sh

touch hello.sh

nastepnie edytujemy utworzony plik dowolnym edytorem np. pico, vi, vim, joe:
pico hello.sh

#wypelniamy nasz pusty plik ponizszym kodem:

#!/bin/bash

#Nastepnie piszemy kod:

echo
"Hello World"


#koniec skryptu

 

Uwaga:
"#" oznacza komentarz w skrypcie. Interpreter kodu pomija wszystko zawarte za # do konca linii, mozemy w ten sposób zamieszczac w skrypcie swoje komentarze.

Zapisujemy zmiany i oto mamy swój pierwszy skrypt, który nalezy uruchomic. Jest kilka sposobów na uruchamianie skryptów. Wiele poradników nakazuje nadac plikowi prawo wykonania aby go uruchomic - owszem jest to poprawne jednak nie niezbedne, skrypty mozemy uruchamiac na kilka sposobów, najprostszy sposób uruchomienia skryptu to wydanie komendy sh (dla bash): sh skrypt.sh - taki sposób uruchamiania skryptu pozbawia nas potrzeby umieszczania na poczatku kodu definicji powloki #!/bin/bash, poniewaz sh oznacza: wykonaj skrypt w powloce bash. Jezeli nie podamy w skrypcie definicji powloki, ani tez nie wykonamy skryptu poleceniem sh, skrypt nasz zostanie wykonany w domyslnej powloce w jakiej wlasnie jest wywolywany, w linuksie zazwyczaj domyslna powloka jest bash.
W naszym przykladzie zakladajac ze jestesmy w tym samym katalogu co nasz skrypt wydajemy polecenie:

sh hello.sh 

w przeciwnym wypadku musimy podac pelna sciezke dostepu do skryptu:

sh /home/user/skrypty/hello.sh

co nam wyswietli na wyjsciu, na monitorze tresc:

Hello World

Inny sposób wykonania skryptu, to nadanie mu prawa, atrybutu do wykonania czyli:


chmod + x hello.sh

nastepnie aby wykonac skrypt wystarczy wydac polecenie:

./hello.sh
 
#lub
 
. /home/user/skrypty/hello.sh

Kolejnym sposobem uruchamiania skryptów jest nadanie im praw do wykonania i umieszczenia sciezki do skryptu w zmiennej PATCH, lub np. skopiowanie skrytu do katalogu /usr/sbin, wtedy wykonujemy nasz skrypt tak jak inne programy zawarte w naszym systemie, wydajac po prostu polecenie:

hello.sh 

Nazwa naszego pliku hello.sh posiada rozszerzenie .sh które nie jest konieczne, jednak dobrym nawykiem jest nadawanie skryptom rozszerzen w celu latwiejszego ich identyfikowania przez nas samych jak i przez róznego rodzaju edytory podswietlajace skladnie kodu, np. edytor zawarty w midnight commanderze rozpoznaje rodzaj kodu po rozszerzeniu pliku i w sposób wygodny dla nas podswietla skladnie kodu podczas edycji skryptu.

  • Ciekawostka:
Ogólnie #!/bin/powloka wcale nie musi byc powloka, moze byc dowolnym poleceniem, np. nastepujacy skrypt sam sie kasuje:
#!/bin/rm
 
#Zawartosc skryptu nie jest istotna
#jakies tam polecenia
 
#End script

Powloka rozwinie to nam w /bin/rm ./nazwa_skryptu, czyli skasuj hello.sh

Do spisu tresci
Polecenie ECHO

Echo jest poleceniem wyswietlajacym na ekranie swoje argumenty.
Skladnia:
#!/bin/bash
 
echo "jakis tekst" #wydrukuje na ekranie: jakis tekst
 
#End script
 

 

Parametry ECHO:
-n
-e
\a
\b
\c
\e
\f
\n
\r
\t
\v
\\
\nnn
\xnn
: nie jest wysylany znak nowej linii (kursor pozostaje w tej samej linii)
: wlacza inetrpretacje znaków specjalnych takich jak:
: alert, brzeczyk systemowy
: backspace
: to samo co -n
: escape
: line feed
: form feed czyli wysuw strony, nowa linia
: znak nowej linii powrót karetki (\f\r daje to samo co \n)
: tabulacja pozioma
: tabulacja pionowa
: backslash
: znak, którego kod ASCII ma wartosc ósemkowa
: znak, którego kod ASCII ma wartosc szesnastkowa
Przyklad:
echo -n "przykladowy tekst"
Jako ze w powloce znak backslash jest znakiem specjalnym, musimy go podwoić, badz wpisywac ciagi znaków w cudzyslowach.

Przyklad:
#!/bin/sh echo -e \\a
 
sleep 1 #wstrzymanie skryptu na 1 sekunde
echo "peep"
echo -e "\a"
 
Here-Documents
'Here documents' - dokumenty miejscowe. Jest to rodzaj przekierowania, które pozwala czesc tresci skryptu traktowac jako standardowe wejscie.

Skladnia:
<
here-document
ogranicznik
Przyklad:
#!/bin/sh
cat << KONIEC
 
Ten tekst zostanie
wyswietlony na ekranie
ogranicznikiem jest KONIEC
 
KONIEC

Po wykonaniu powyzszego skryptu otrzymamy na ekranie wszystko to co zawarlismy miedzy wyrazami KONIEC. Ten sposób moze byc uzywany do wyswietlenia wiekszej ilosci informacji na ekran bez koniecznosci wpisywania echo w kazdej linii. W dokumencie miejscowym dokonuje sie wszystkich rozwiniec. Ogranicznik koncowy musi znalezc sie sam w jednej linii, dlatego ostatnie slowo KONIEC pojawia sie na ekranie. Pierwszy ogranicznik moze byc dowolnym wyrazeniem, szczególy w podreczniku systemowym.

Slowa zastrzezone (ang. reserved words)
Tak jak w kazdym jezyku programowania tak samo i w bashu wystepuja slowa zastrzezone, zarezerwowane, które maja dla powloki specjalne funkcjonalne znaczenie, wtedy gdy nie sa cytowane. Glówne slowa to:
! case do done elif else esac fi for function if in select then until while { } time [ ] 

Do spisu tresci

Polecenie sleep i exit
Polecenie sleep powoduje wstrzymanie wykonywania instrukcji skryptu na okreslony czas:
#!/bin/bash
 
echo "teraz wstrzymam skrypt na 10 sekund"
sleep 10
echo "koniec papa..."
 
#End script
 
 
Polecenie exit
Polecenie exit powoduje natychmiastowe zakonczenie skryptu bez wzgledu na miejsce wywolania. Dodatkowy parametr pozwala udostepnic otoczeniu kod wyjscia, który moze nalezec do przedzialu 0 - 125, przy czym zero jest traktowane jako sukces. Kody powyzej 125 sa zarezerwowane i maja nastepujace znaczenie:
Kody wyjscia > 125
126 - plik nie mial atrybutu wykonywalnosci "x"
127 - nie znaleziono pliku o zadanej nazwie
128 i w góre powodem zakonczenia byl jakis sygnal (wartosc kodu wyjscia równa jest 128 + numer sygnalu)

Piszac skrypty niejednokrotnie zalezy nam aby skrypt po zakonczeniu pracy, w zaleznosci od tego jakie czesci skryptu sie wykonaly zwrócil odpowiedni status. A wiec jesli skrypt zakonczyl dzialanie bez bledu zwróci nam status 0, natomiast jak cos pójdzie nie tak zwróci 1. A co jezeli polowa skryptu wykona sie prawidlowo natomiast druga nie wykona sie wcale a my chcemy o tym wiedziec - wtedy mozemy zastosowac exit z odpowiednimi statusami.
Przyklad:
#!/bin/bash
 
#przenies zosia na mundek (zmien nazwe)
 
mv zosia mundek
if [ $? -eq 0 ]
then echo "Powodzenie"
else echo "blad"; exit 4
fi
 
#tutaj moze byc dalsza czesc skryptu do wykonania
 
echo "papa"
 
#End script
 

Jezeli np. plik zosia nie istnieje to mamy niepowodzenie w wykonaniu skryptu i chcemy zeby w takim przypadku skrypt po zakonczeniu zglosil kod 4. Jezeli natomiast polecenie mv zadziala bez bledu to zwróci kod 0, instrukcja if sprawdzi czy status dzialania polecenia mv jest równy 0 i wyswietli powodzenie, oraz skrypt bedzie wykonywany dalej i zakonczy sie powodzeniem i statusem 0, w przeciwnym wypadku wykona sie druga czesc instrukcji - skrypt wyswietli tekst "blad" i wykonujac polecenie exit ze statusem 4 przerwie dzialanie a dalsza czesc skryptu juz se nie wykona.

Potoki i przekierowania

Potoki i przekierowania pozwalaja zmieniac standardowe wejscie, wyjscie oraz standardowe wyjscie bledów lub laczyc je w potoki. Mozna przekierowywac dowolne z deskryptorów, jednak w wiekszosci przypadków wykorzystywane sa jedynie na standardowych wejsciach i wyjsciach.
Skladnia potoku:
polecenie1 | polecenie2 | polecenie3 | polecenien...
Potok jest ciagiem polecen porozdzielanych znakiem "|", przy czym standardowe wyjscie polecenia poprzedzajacego jest standardowym wejsciem polecenia nastepnego.
Przyklad:
$ /sbin/ifconfig | grep HWaddr > wynik.txt
Jak widac pierwsze polecenie wywoluje polecenie ifconfig nastepnie polecenie drugie - program grep wyodrebnia z wyniku dzialania ifconfig jedynie linie zawierajaca adres MAC karty sieciowej i caly wynik dzialania potoku jest zapisywany do pliku o nazwie wynik.txt - ta ostatnia operacja to wlasnie przekierowanie...
Przekierowania
Deskryptor (ang. descriptor) - struktura definiujaca okreslony obiekt w pamieci.
Przed wykonaniem polecenia powloka sprawdza, czy nie powiazac okreslonych deskryptorów innymi, badz z plikami. Przekierowanie wejscia [n] < plik powoduje otwarcie pliku do czytania i powiazanie deskryptora o numerze n z zawartoscia pliku. Jesli pominiemy numer deskryptora powloka przekieruje standardowe wejscie (deskryptor nr 0).
Przyklad:
$ mail jakis@adres.com This e-mail address is being protected from spambots, \
you need JavaScript enabled to view it < wiadomosc.txt

Przekierowanie wyjscia [n] > plik powoduje otwarcie pliku do pisania i powiazanie go z deskryptorem o numerze n. Jesli plik nie istnieje zostanie stworzony, jesli istnieje zostanie skrócony do zera (patrz opcja noclobber). Gdy pominiemy numer deskryptora powloka przekieruje standardowe wejscie (deskryptor nr 1). Przekierowanie wyjscia z dopisywaniem [n] >> plik powoduje otwarcie pliku do dopisywania (jesli nie istnieje zostanie stworzony) i powiazanie go z deskryptorem o numerze n. Gdy pominiemy numer deskryptora powloka przekieruje standardowe wejscie. Przekierowanie wyjscia i standardowego wyjscia &> plik powoduje otwarcie pliku do pisania i powiazanie go ze standardowym wyjsciem i standardowym wyjsciem bledów. Powyzsze definicje nie zbyt jasno tlumacza róznice miedzy przekierowaniem wyjscia i wejscia. Na przekierowanie wejscia mozna patrzec w ten sposób, ze czytajac z danego deskryptora bedziemy czytali z pliku, a w przypadku przekierowania wyjscia piszac do danego deskryptora wynik znajdzie sie w pliku. Przekierowan wejscia rzadziej sie uzywa, gdyz wiekszosc polecen pozwala podac jako parametr plik wejsciowy zamiast standardowego wejscia.

Przyklad:
$ find / -size +500k -xdev >& duze_pliki

Wpisujac powyzsza linijke w pliku duze_pliki dostaniemy liste plików biezacego systemu plików zajmujacych conajmniej 500 kilobajtów. W pliku tym zostana tez umieszczone komunikaty o bledach. Duplikowanie deskryptorów. Wywolanie [n] && [m] piszac do deskryptora [n]

piszemy do deskryptora [m].
Przyklad:
$ find / -size +500k -xdev > duze_pliki 2>&1

Wywolanie to jest równowazne wczesniejszemu. Standardowe wyjscie jest powiazane z plikiem duze_pliki, a standardowe wyjscie bledów ze standardowym wyjsciem - prosciej jesli chcemy wyeksportowac do tego samego pliku wynik dzialania programu wraz z bledami stosujemy takie wlasnie przekierowanie 2>&1.

Opcja "noclobber"

Wlaczenie opcji:
set -o noclobber lub set -C

Po wlaczeniu tej opcji jesli w przekierowaniach &gr; plik i >& plik plik istnieje, to zostanie wyswietlony blad. Zabezpiecza to przed przypadkowym nadpisaniem istniejacego pliku. Aby zapisac do istniejacego pliku nalezy wylaczyc opcje 'noclobber' (set +o noclobber lub set+C) lub tez uzyc przekierowania >| plik.

Przyklad:
$ touch plik
$ set -o noclobber
$ ls > plik
bash: plik: cannot overwrite existing file
$ ls >| plik
$ set +C
$ echo koniec > plik
 

Do spisu tresci


Zmienne
W przeciwienstwie do wiekszosci jezyków programowania w skryptach nie deklaruje sie zmiennych przed ich zastosowaniem. Ich pierwsze uzycie jest jednoczesnie ich deklaracja. Nazwa zmiennej moze byc dowolnym identyfikatorem, przy czym wazna jest wielkosc liter i zmienne VARIABLE i variable sa rózne. Aby odwolac sie do zawartosci zmiennych trzeba przed nazwa zmiennej napisac znak $. Istotne jest takze to, ze zmienne sa pamietane przez powloke jako ciagi znaków, dopiero odpowiednie polecenia interpretuja te ciagi w odpowiedni sposób.
Przyklad:
$ ile=5
$ echo ile
ile
$ echo $ile
5
$ ile=5+5 # 5+5 jest ciagiem znaków
$ echo ile
5+5
$

Do spisu tresci


Zmienne srodowiskowe

W skrypcie mozemy sie odwolac do zmiennych srodowiskowych w sposób identyczny do zwyklych zmiennych, piszac znak dolara przed nazwa zmiennej. Aby zobaczyc liste zmiennych zdefiniowanych w systemie wpisz w powloce polecenie env.
Przykladowe zmienne:

$HOME
$PATH
$PS1
$IFS
: katalog domowy uzytkownika
: lista katalogów przeszukiwana przez polecenia
: znak zgloszenia powloki
: separator pola wejscioweg, wszystkie znaki z tej zmiennej uzywane sa do oddzielania slów na wejsciu
$ IFS=":"
$ read x y z
1:2:3
$ echo x=$x y=$y z=$z
x=1 y=2 z=3
 
$ read x y z
1 2 3
$ echo x=$x y=$y z=$z
x=1 2 3 y= z=
 
$ IFS=" :"
$ read x y z
1:2 3
$ echo x=$x y=$y z=$z
x=1 y=2 z=3
 
$ IFS=":,"
$ read x y z
1,2:3
$ echo x=$x y=$y z=$z
x=1 y=2 z=3
 
$ read x,y,z *
1:2:3
bash: read: `x,y,z`: not a valid identifier
 
$ d=`x,y,z`
$ read $d **
1:2:3
$ echo x=$x y=$y z=$z
x=1 y=2 z=3
 
$ read "$d" ***
1:2:3
bash: read: `x,y,z`: not a valid identifier

Kilka ostatnich linijek z pewnoscia wprowadzilo troche zamieszania i wymaga wytlumaczenia. Powloka przeszukuje rezultaty rozwiniec parametrycznych, rozwiniec polecen w apostrofach i rozwiniec arytmetycznych w poszukiwaniu znaków ze zmiennej IFS { (*)-nie jest rozwinieciem}. Jesli takie znajdzie zamienia je na spacje (**). Jesli jednak calosc ujmiemy w cudzyslowy nie dojdzie do zamiany (***).


#!/bin/sh
IFS=:
echo "$*"
echo $*
echo $@
echo $1 $3
Wykonujac skrypt z parametrami: raz dwa trzy otrzymamy wynik:
raz:dwa:trzy
raz dwa trzy
raz dwa trzy
raz trzy
Polecenie unset
Polecenie unset anuluje przypisania zmiennym wartosci usuwajac te zmienne ze srodowiska.
Mozna równiez je stosowac do funkcji.
Przyklad:
$ zmienna=5
$ echo $zmienna
5
$ unset zmienna
$ echo $zmienna
$


Do spisu tresci
Polecenie EXPORT
To co przypiszemy zmiennym ginie po jego zakonczeniu, a to dlatego, ze uruchamiajac skrypt dostajemy nowe srodowisko i wszelkie przypisania zmiennych dotycza tego srodowiska. Uruchamiajac jakis inny proces z naszego skryptu dziedziczy on nasze srodowisko, ale po zakonczeniu skryptu wszystko znika. Istnieje jednak polecenie export, któro pozwala zmienic srodowisko procesu rodzica. Czesto to polecenie jest wykorzystywane w pliku konfiguracyjnym powloki (np. dla bash'a bedzie to /etc/bashrc i w katalogu uzytkownika .bashrc).
Skladnia:
export zmienna
lub
export zmienna=wartosc

Przyklad:
export PATH=$PATH:$HOME/bin
export DISPLAY=localhost:10.0
 
export ORACLE_BASE=/u01/app/oracle
ORACLE_HOME=$ORACLE_BASE/product/11.0.2
export ORACLE_HOME


Zmienne parametryczne:

$?
$$
$0
$#
$*
$@
$1,$2..
- Kod powrotu ostanio wykonywanego polecenia
- PID procesu bieżącej powłoki
- nazwa wykonywanego skryptu
- liczba przekazanych parametrów
- lista parametrów porozdzielanych pierwszym znakiem ze zmiennej $IFS, przykład ponieżej
- lista parametrów porozdzielanych spacjami
- poszczególne parametry w kolejności podanej przy uruchamianiu skryptu

Przykład:

#!/bin/sh
IFS=:
echo "$*"
echo $*
echo $@
echo $1 $3

 

Wykonując skrypt z parametrami: raz dwa trzy otrzymamy wynik:
raz:dwa:trzy
raz dwa trzy
raz dwa trzy
raz trzy


Polecenie unset


Polecenie unset anuluje przypisania zmiennym wartości usuwając te zmienne ze środowiska.
Można również je stosować do funkcji.

Przykład:
$ zmienna=5
$ echo $zmienna
5

$ unset zmienna
$ echo $zmienna
$

Do spisu tresci


Cudzyslowy i apostrofy

Cudzyslowy

Istnieja dwa rodzaje cudzyslowów: " " (podwójne) i ' ' (pojedyncze). Istnieja jeszcze ` (apostrofy) omówione w nastepnym rozdziale. Cudzyslowów umozliwiaja przypisanie zmiennej ciagu zawierajacego spacje. Normalnie powloka traktuje spacje jako separatory parametrów. Jesli w poprzednim skrypcie chcielibysmy przekazac jako parametr ciag zawierajacy spacje, musielibysmy wywolac skrypt nastepujaco:

./nazwa_skryptu raz 'dwa trzy' cztery
 
co po wykonaniu daloby nam:
 
raz:dwa trzy:cztery
raz dwa trzy cztery
raz cztery
 

Cudzyslowy " " i ' ' róznia sie tym, ze w przypadku tych pierwszych powloka rozwija wszystkie nazwy zmiennych w wartosci tych zmiennych (rozwiniecia parametryczne), rozwija tez polecenia w apostrofach (patrz Apostrofy dalej) oraz odpowiednio traktuje pewne znaki poprzedzone backslashem '\'. Nie jest tak w przypadku drugich apostrofów. Dodatkowo jesli chcemy miedzy cudzyslowami " " uzyc tego samego cudzyslowu, musimy poprzedzic go backslashem \. Nie dotyczy to cudzyslowów pojedynczych, gdyz znak cudzyslowu po backslashu bedzie traktowany jako koniec lancucha. Nic nie stoi jednak na przeszkodzie, by wewnatrz cudzyslowów " " uzywac ' ' i odwrotnie. Aby nie doszlo do rozwiniecia zmiennej w cudzyslowach podwójnych mozemy znak dolara poprzedzic backslashem \. Aby otrzymac backslash musimy napisac go podwójnie. Oczywiscie w cudzyslowach pojedynczych nie dojdzie do zadnego rozwiniecia.


Przyklad:

$ kat='$HOME'
$ echo $kat
$HOME
$ echo "\$HOME"
$HOME
$ kat="$HOME"
$ echo $kat
/home/radek
$ kat='Cudzyslów " podwójny'
$ echo $kat
Cudzyslow " podwójny
$ kat="Cudzyslów \" podwójny"
Cudzyslów " podwójny

Ponizej wymienione sa sekwencje poprzedzone backslashem zamieniane wewnatrz cudzyslowów podwójnych.
Pozostale sekwencje poprzedzone backslashem (wymienione przy poleceniu echo) nie sa zamieniane.




Apostrofy

Apostrofy ( ` ` ) maja calkiem odmienne od cudzyslowów znaczenie.
Powloka wykonuje polecenie zawarte miedzy nimi, a wartoscia wyrazenia jest wynik dzialania tego polecenia.

$ data=`date`
$ echo $data
Sun Sep 24 22:37:46 2000
 
#Zamiast dwóch apostrofów mozna zamiennie uzyc konstrukcji: $( ), np.:
data=$(date)
 

Podstawienia komend mozna zagniezdzac.


Do spisu tresci

Obliczanie Wyrazen
Aby obliczyc wyrazenie mozemy skorzystac z zewnetrznego polecenia expr lub uzyc wewnetrznej konstrukcji BASH'a, która jest szybsza gdyz nie potrzebuje oddzielnego procesu i jest wygodniejsza w uzyciu. Czasami trzeba jednak uzyc 'expr', dlatego zostanie pózniej zaprezentowane.



Tych operatorów mozemy uzywac w nastepujacych konstrukcjach:

$((wyrazenie))
((wyrazenie))
let wyrazenie

Dwie ostatnie linijki sa sobie równowazne. Sa one poleceniami w przeciwienstwie do linijki pierwszej, która jest rozwinieciem arytmetycznym i nie moze wystapic samodzielnie. Wystepuje przewaznie po prawej stronie znaku przypisania, w poleceniu 'echo', itp.

Przyklad:
zmienna=0
$ echo $((zmienna=zmienna+2))
2
$ ((zmienna=$zmienna**3));echo $zmienna
8

Do spisu tresci

Rozwiniecia parametryczne

Zalózmy, ze mamy 100 plików o nazwach: plik1.txt, plik2.txt, ... plik100.txt i chcemy te pliki polaczyc w jeden o nazwie plik.txt
Sprawe zalatwi ponizszy skrypt:
#!/bin/sh
zmienna=0
cat /dev/null > plik.txt # tworzenie pustego pliku
while [ zmienna -ne 101 ]; do
zmienna=$(($zmienna+1))
cat plik$zmienna.txt >> plik.txt
done

Jesli jednak nasze pliki nazywaja sie np. plik1XX.txt, plik2XX.txt ... plik100XX.txt, to po modyfikacji linijki cat plik$zmiennaXX.txt >> plik.txt dostaniemy komunikat o braku pliku.

Jak mozna sie domyslic powloka rozwinela zmienna $zmiennaXX, która jest niezdefiniowana. Aby to zadzialalo wystarczy zapisac te linijke w nastepujacy sposób:
cat plik${zmienna}XX.txt >> plik.txt

W ponizszych przykladach slowo moze byc wyrazeniem arytmetycznym, ciagiem znaków, wyrazeniem parametrycznym, poleceniem w odwrotnych apostrofach.


Inne rozwinięcia parametryczne

${parametr:-slowo}

wartością jest wartość zmiennej parametr jeśli
jest ona zdefiniowana i nie jest pusta w

przeciwnym wypadku wartością jest slowo

(zmienna parametr się nie zmienia)

${parametr:=slowo

wartością wyrażenia jest wartość zmiennej

parametr jeśli jest ona zdefiniowana i nie jest

pusta, w przeciwnym wypadku wartością
wyrażenia i zmiennej parametr staje się slowo

${parametr:?slowo}

wartością wyrażenia jest wartość parametru, jeśli
jest on zdefiniowany i nie pusty, w przeciwnym
wypadku wyświetlana jest wiadomość powstała
po rozwinięciu slowo (jeśli pominiemy slowo
zostanie wyświetlony komunikat o tym, że
zmienna parametr jest niezdefiniowana bądź
równa null

${parametr:+slowo}

jeśli parametr jest niezdefiniowany bądź null nic
nie jest podstawiane, w przeciwnym wypadku
wartością jest slowo

${#parametr}

zwraca długość zmiennej parametr w znakach

${parametr#slowo}

zwraca wartość parametru po usunięciu z niego
od początku najkrótszego ciągu pasującego do
słowa

${parametr##slowo}

zwraca wartość parametru po usunięciu z niego
od początku najdłuższego ciągu pasującego do
słowa

${parametr%slowo}

zwraca wartość parametru po usunięciu z niego
od końca najkrótszego ciągu pasującego do słowa

${parametr%%slowo}

zwraca wartość parametru po usunięciu z niego
od końca najdłuższego ciągu pasującego do słowa


Przykład:
!/bin/sh
plik=/etc/lilo.conf
tmp1=${plik##*/}k
tmp2=${plik#*/}
tmp3=${plik%/*}
echo $plik
echo $tmp1
echo $tmp2
echo $tmp3
 
#Wykonanie skryptu spowoduje wypisanie następujących linii:
 
/etc/lilo.conf
lilo.conf
etc/lilo.conf
/etc

Przykład:
#!/bin/sh
line=`grep ^root /etc/passwd`
echo Shell roota: ${line##*:}

 

Do spisu tresci

Polecenie "test"

Polecenie to ma wiele opcji i jest często wykorzystywane w skryptach do realizowania różnych warunków logicznych, gdyż zawsze zwraca wartość logiczną.
Posiada dwa rodzaje składni, np.:
$ if test -f /etc/passwd; then
> echo "plik passwd istnieje w /etc"
> fi

jest równoważne wykonaniu:

 

$ if [ -f /etc/passwd ]; then
> echo "plik passwd istnieje w /etc"
> fi

Należy pamiętać o istotnym szczególe, mianowicie o pozostawieniu przynajmniej po jednej spacji po nawiasie otwierającym i przed zamykającym.

  • Opcje które mogą pojawić się po słowie test lub w nawiasach:
  • (Po prawej stronie wypisane są sytuacje, kiedy polecenie zwraca prawdę)

 

Porównanie ciągów

lancuch

ciąg nie jest pusty

lancuch1 = lancuch2, lancuch == lancuch2

ciągi są jednakowe

lancuch1 != lancuch2

ciągi są różne

-n lancuch

ciąg nie jest pusty

z lancuch

ciąg jest pusty

Porównania arytmetyczne

wyr1 -eq wyr2

wyrażenia są równe

wyr1 -ne wyr2

wyrażenia są różne

wyr1 -gt wyr2 wyr1

jest większe od wyr2

wyr1 -ge wyr2 wyr1

jest większe równe od wyr2

wyr1 -lt wyr2 wyr1

jest mniejsze od wyr2

wyr1 -le wyr2 wyr1

jest mniejsze równe od wyr2

wyr1 -a wyr2

wyrażenia 1 i 2 są prawdziwe (AND)

wyr1 -o wyr2

jedno z wyrażeń jest prawdziwe (OR)

! wyr

wyrażenie jest zerowe

Sprawdzenia plików

-a plik

plik istnieje

-b plik

plik jest urządzeniem blokowym

-c plik

plik jest urządzeniem znakowym

-d plik

plik jest katalogiem

-e plik

plik istnieje

-f plik

plik jest plikiem regularnym

-g plik

plik z ustawionym bitem SGID

-h plik

plik jest linkiem symbolicznym

-G plik

plik, którego GID właściciela = EGID

-k plik

plik z ustawionym bitem sticky

-L plik

plik jest linkiem symbolicznym

-O plik

plik, którego UID właściciela = EUID

-p plik

plik jest łączem nazwanym (PIPE)

-r plik

plik jest odczytywalny

-s plik

plik ma niezerową wielkość

-S plik

plik jest gniazdem

-u plik

plik z ustawionym bitem SUID

-w plik

plik jest zapisywalny

-x plik

plik jest wykonywalny

plik1 -ef plik

pliki mają ten sam numer urządzenia oraz i-węzła

plik1 -nt plik2

plik1 jest młodszy niż plik2

plik2 -ot plik2

plik1 jest starszy niż plik2

Inne

-o nazwa opcji

opcja powłokinazwa opcjijest włączona

 

Jest jeden szczegół o którym warto pamiętać używająć opcji -G i -O. Można nadać skryptowi bit SUID i SGID, ale nie jest on honorowany. Dlatego skrypcie EUID (efektywny ID) jest równy UID (rzeczywisty ID).

Nie zapominajmy o spacjach przed i po znakach równości i różności w warunkach. Może być kilka niejasności odnośnie niektórych warunków dotyczących sprawdzania plików, ale nie to jest przedmiotem tego kursu i nie zostaną tu wyjaśnione. W większości wypadków wystarczy znać opcje z literami: d, f, r, s, w, x. Rolę spójników logicznych AND i OR pełnią odpowiednio operatory: -a i -o, np. [ wyr1 -a wyr2 -o wyr3 ].

Polecenie 'test' jest poleceniem zewnętrznym dla powłoki. '[' jest linkiem symbolicznym do polecenia test. Pisząc więc [ wyrażenie ] zostaje wywołane polecenie test z dodatkowym argumentem ']'. Istnieje jednak wewnętrzna konstrukcja w BASH'u, która pozwala obliczać wyrażenia logiczne.

  • Składnia:

[[ wyrażenie ]]

Przyjmuje ona taki sam zestaw opcji oprócz spójników logicznych AND i OR, którymi są tu odpowiednio && i ||

Do spisu tresci


Polecenie 'expr'

Jak mówi podręcznik systemowy, polecenie expr wykonuje obliczenie wyrażenia i zapisuje je na standardowe wyjście. Jako, że jest to polecenie zewnętrzne dla powłoki wykorzystuje się je wpisując w odwrotne apostrofy, bądź w równoważną im konstrukcję $(polecenie).

  • Przykład:
$ ile=5
$ ile=`expr $ile + 5`
$ ile=$(expr $ile + 5)
$ echo $ile
15
 

 

Polecenie przyjmuje w parametrze ciąg operandów i operatorów, które muszą być porozdzielane spacjami.

Operandy mogą być liczbami bądź ciągami znaków.

Operatory
| , & operatory logiczne OR (gdy wynik nie jest zerem zwracany jest pierwszy niezerowy argument) i AND(gdy wynik nie jest zerem zwracany jest pierwszy z argumentów)
+ , - , * , / , % operatory arytmetyczne (odpowiednio: dodawanie, odejmowanie, mnożenie, dzielenie całkowite, dzielenie modulo)
operatory porównania (operatory: '=' i '==' są równoważne)
: dokonuje porównania wzorców, oba argumenty rzutowane są na napisy przy czym drugi z argumentów może być wyrażeniem regularnym w postaci akceptowalnej przez GREP'a. Jeśli wzorce pasują do sieie zwracana jest długość napisu, jeśli nie, zwracane jest zero. Dodatkowo jeśli w drugim argumencie umieszczona zostanie jednapara nawiasów '\(' i '\)', to w przypadku pasowania wzorców zostanie zwrócony napis zawarty między tymi nawiasami lub napis pusty w przypadku przeciwnym.
rozpoznawane słowa kluczowe

match napis wyr_ regularne

to samo co 'napis : wyr regularne'

substr napis pozycja długość

zwraca podnapis z podanego napisu o podanej długości i zaczynający się od podanej pozycji

index napis znaki

zwraca pozycję wystąpienia tego znaku ze zbioru znaków będącego drugim argumentem, którego zajmuje najniższą pozycję w napisie
length napis zwraca długość napisu


Przykłady:

$ napis='Ala ma kota'
$ expr index "$napis" k
8
$ expr index "$napis" A
1
$ expr index "$napis" kA
1
$ expr substr "$napis" 8 3
kot
$ expr match "$napis" 'Ala ma kota'
11
$ expr "$napis" : 'Ala ma psa'
0
$ expr "$napis" : 'Ala .*' # wyrażenie regularne
11
$ expr "$napis" : 'Ala ma \(kot\)a'
kot

Do spisu treści


Konstrukcja 'if'

Jest to instrukcja warunkowa, z którą każdy, kto programował w jakimś języku programowania musiał się zetknąć.

Składnia polecenia:

if warunek

then

instrukcje

else

instrukcje

fi

Jako że jesteśmy przyzwyczajeni do pisania else w tej samej linii co if, możemy tak dalej robić, tylko musimy oddzielić instrukcję if warunek od then średnikiem, gdyż inaczej powłoka traktuje then jako dokończenie warunku.

  • Przykład:

 

$ if [ -f /etc/passwd ]; then echo plik_istnieje ; else echo Ups; fi
  • W przypadku złożonych warunków słowa else if stojące obok siebie można złączyć w słowo elif.

Poniższy skrypt drukuje największą z trzech liczb przekazanych jako parametry:

#!/bin/sh
if [ $1 -ge $2 ]; then
if [ $1 -ge $3 ]; then echo $1
else echo $3
fi
elif [ $2 -ge $3 ]; then echo $2
else echo $3
fi
 
  • Wykonajmi poniższe polecenia, niech imie będzie zmienną niezainicjowaną.

 

$ if [ $imie = "franek" ]
> then echo Cze_franek
> fi
[: =: unary operator expected
 

Ostatni komunikat błędu spowodowany jest tym, że zmienna imie jest niezainicjowana, wobec czego warunek w nawiasach staje się warunkiem [ = "franek" ]. Czyli brakuje jednego parametru. Problem rozwiąże następujący zapis: [ "$imie" = "franek" ], a warunek staje się warunkiem [ "" = "franek" ].

Do spisu treści

Listy AND i OR

Lista AND

Składnia

instrukcja1 && instrukcja2 && instrukcja3 && instrukcja4 ...

Wykonywane są instrukcje po kolei aż do momentu określenia wyniku całości wyrażenia, czyli jeśli np. instrukcja1 zwróci FALSE, to instrukcja2 się już nie wykona, a całość wyrażenia przyjmie wartość FALSE. Aby otrzymać TRUE, wszystkie spośród instrukcji muszą zwrócić TRUE, w tym wypadku wszystkie one zostaną wykonane. Zamiast instrukcji może wystąpić dowolne wyrażenie, wtedy zamiast wykonywania instrukcji zostanie obliczona wartość tego wyrażenia. Całość można traktować jako ciąg iloczynów logicznych przetwarzany od lewej do prawej, w którym instrukcje są wykonywane dopóki wartość wyrażenia nie jest jeszcze określona.


Lista OR

  • Składnia:

instrukcja1 || instrukcja2 || instrukcja3 || instrukcja4 ...

Analogicznie jak w przypadku listy AND instrukcje są wykonywane do momentu określenia całości wyrażenia, tylko w tym przypadku jest odwrotnie, mianowicie jeśli dowolna z instrukcji przyjmie wartość TRUE, to wartość wyrażenia będzie określona jako TRUE i dalsze instrukcje się nie wykonają. Zwrócenie przez instrukcję FALSE powoduje dalsze przetwarzanie wyrażenia. Aby otrzymać FALSE, wszystkie instrukcje muszą zwrócić FALSE.

Wyrażenie można traktować jako ciąg sum logicznych. Można łączyć ze sobą listy AND i OR, by uzyskać bardziej skomplikowane warunki. Żaden z operatorów && i || nie ma wyższego priorytetu od drugiego. Całość wyrażenia jest wykonywana sekwencyjnie od lewej do prawej, jeśli chcemy to zmienić można użyć nawiasów zwykłych.

  • Przykład
$ [ -f /etc/passwd ] && echo Ufff || echo Ups
Ups Laughing

Przykład:

#!/bin/sh
$1 -ge $2 ] && ( [ $1 -ge $3 ] && echo $1 || echo $3) || \
([ $2 -ge $3 ] && echo $2) || echo $3

Powyższy skrypt wyświetla na ekran największy z 3 podanych mu parametrów. Nowy element pojawił się w 2 wierszu w przykładzie 2 na końcu linii - backslash. Postawienie znaku backslash \ na końcu wiersza informuje powłokę, że dana linijka jest kontynuowana w następnym wierszu (normalnie następny wiersz to następna instrukcja). Dzięki temu nie musimy pisać długich wierszy, które przeszkadzają w wygodnym edytowaniu i oglądaniu pliku (nie wszystkie edytory obsługują automatyczne zawijanie).

 

Do spisu treści

Blok instrukcji

Wszędzie tam, gdzie musimy użyć pojedynczej instrukcji, możemy zastosować blok instrukcji, czyli ciąg instrukcji ujęty w nawiasy klamrowe lub zwykłe.

  • Składnia:

{ ciąg poleceń; }

lub

(ciąg poleceń)

 

W przypadku nawiasów klamrowych polecenia są wykonywane w bieżącej powłoce i środowisku. Wartością takiego bloku jest wartość ostatniej instrukcji. Dla poleceń w nawiasach zwykłych tworzona jest nowa powłoka. Wartością zwracaną jest kod ostatniej instrukcji bądź wartość zwrócona przez komendę 'exit'.

  • Przykład:
$ if true && { false;false;true }
> then echo TRUE
> fi
TRUE
 
$ if true && (false;false;exit 0)
> then echo TRUE
> fi
TRUE
 

true i false są poleceniami zwracającymi odpowiednio prawdę i fałsz. Dodatkowo false jest często wpisywane w /etc/passwd w ostatniej kolumnie, by uniemożliwić użytkownikowi wejście na shella. Zamiast polecenia true może też wystąpić : (pojedynczy dwukropek), któro jest poleceniem pustym zwracającym prawdę, np.

 

$ while :
> do echo -e \\a
> done
 

Do spisu treści

 

Konstrukcja 'case'

  • Składnia polecenia:

case zmienna in

ciag_wzorca [ | ciag_wzorca ] ... ) ciag_instrukcji ;;

ciag_wzorca [ | ciag_wzorca ] ... ) ciag_instrukcji ;;

...

esac

Polecenie to działa w ten sposob, że dopasowuje zmienną po kolei do wzorcow i po udanym dopasowaniu wykonuje ciąg instrukcji przyporządkowany temu wzorcowi. Jeśli zmienna pasuje do kilku wzorcow, wykona się tylko pierwszy. W przypadku, gdy nie pasuje do żadnego wzorca nic się nie wykona. Aby wykonała się jakaś czynność domyślna stosuje się znak * jako wzorzec. Wzorzec ten pasuje do każdej wartości zmiennej, należy więc pamietać, by wpisać go na końcu. Przy stosowaniu polecenia należy się kierować zasadą, by bardziej ogólne wzorce umieszczać dalej. Najlepiej jednak zobaczyć to na przykładzie,

  • Przykład:
#!/bin/sh
echo Czy chcesz kontynuować?
read x
case $x in
"tak" | "TAK" | "T" | "t" ) echo Wpisałeś tak;;
"nie" | "NIE" | "N" | "n" ) echo Wpisałeś nie;;
* ) echo Nie wiem co wpisałeś;;
esac
 

 

Skracając i uogólniając powyższe warunki otrzymamy poniższy skrypt. Wtedy do pierwszego wzorca pasuje litera T lub t lub napis "tak" w którym dowolna z jego liter może być mała lub duża.

 

#!/bin/sh
echo Czy chcesz kontynuować?
read x
case $x in
[Tt][Aa][Kk] | [Tt] ) echo Wpisałeś tak;;
[Nn][Ii][Ee] | [Nn] ) echo Wpisałeś nie;;
* ) echo Nie wiem co wpisałeś;;
esac

 

Do spisu treści

 

Pętla 'for'

  • Składnia polecenia

for zmienna in zbiór_wartości do

instrukcje

done

 

Pętla FOR działa w ten sposób, że dla każdego elementu ze zbioru wartości przypisuje go do zmiennej i wykonuje instrukcje zawarte wewnątrz pętli.

Zbiór wartości nie musi być podany jawnie, może być rozwinięty przez powłokę, np.:

  • Przykład:
#!/bin/sh
for zm in *
do
if [ -u $zm ]
then echo $zm
fi
done
 
 

W tym wypadku powłoka rozwija znak * w listę plików z bieżącego katalogu. Powyższy skrypt drukuje na ekranie pliki, które mają ustawiony bit SUID. Poniższy przykład pokazuje jak wysłać do wszystkich użytkowników systemu posiadających konta shellowe z powłoką /bin/bash. Pamiętajmy o odwróconych cudzysłowach.

 

#!/bin/sh
for user in `cat /etc/passwd | grep /bin/bash | cut -d : -f -1`
do
echo "Cześć mam do sprzedania fortepian" | mail -s "Spam" $user
done
 

 

Do spisu treści

 

Pętla 'while'

  • Składnia polecenia

while warunek

do

instrukcje

done

 

Warunek sprawdzany jest przed wywołaniem instrukcji. Instrukcje będą wykonywane dopóki warunek jest prawdziwy.

  • Przykład:
#!/bin/sh
i=1
while [ $i -le 5 ]; do
echo "$i) Opcja $i"
i=$(($i+1))
done
 

 

Do spisu treści

 

Pętla 'until'

  • Składnia polecenia

until warunek

do

instrukcje

done

 

Pętla ta jest podobna do pętli WHILE z tą różnicą, że instrukcje są wykonywane dopóty warunek jest fałszywy. Jeśli warunek staje się prawdziwy pętla jest przerywana.

  • Przykład:
#!/bin/sh
until who | grep root > /dev/null
do
sleep 2
done
echo -e \\a
echo "**** root sie zalogowal ****"
 
 
 

Ten skrypt co 2 sekundy sprawdza, czy do systemu zalogował się root. Jeśli tak, to powiadamia nas i kończy działanie. Jeśli w momencie uruchomienia skryptu root jest już w systemie, instrukcje w pętli UNTIL nie wykonają się ani razu.

 

Do spisu treści

 

Pętla 'select'

  • Składnia polecenia

select zmienna [ in zbiór_wartości ]

do

instrukcje

done

Zbiór wartości jest wyświetlany na standardowym wyjściu, każdą pozycję poprzedza numer. Jeśli pominiemy in zbiór_wartości wyświetlone zostaną parametry pozycyjne (parametry przekazane do skryptu bądź parametry przekazane funkcji). Wyświetlany jest następnie znak zachęty systemu (ze zmiennej PS3) i powłoka oczekuje na wprowadzenie numeru. Jeśli wprowadzimy poprawny numer zmienna z polecenia otrzyma wartość odpowiadającą temu numerowi, jeśli nie jest to numer, bądź numer jest błędny zmienna ta otrzyma wartość NULL. Następnie wykonywane są instrukcje wewnątrz bloku. Potem wszystko zaczyna się od początku. Aby wyjść z pętli należy wśród instrukcji wstawić polecenie break lub return lub też wprowadzić znak EOF. Dodatkowo wprowadzona przez nas linia jest pamiętana w zmiennej REPLY.

  • Przykład:
$ select plik in *
> do
> echo Wpisana linia: $REPLY
> Wybrałeś $plik
> break
> done

Do spisu treści

 

Polecenia 'break' i 'continue'

Oba polecenia służą do wcześniejszego wyjścia z aktualnego przebiegu pętli, z tą różnicą, że po wykonaniu BREAK wykonywanie pętli kończy się całkowicie podczas, gdy po wykonaniu CONTINUE pomijane są polecenia za CONTINUE i wykonywany jest następny przebieg pętli. Najlepiej zobaczyć to na przykładzie,

  • Przykład:
#!/bin/sh
tymczasowy='names.$$$'
cat /dev/null > $tymczasowy
 
for zm in *
do
if [ -d $zm ] || [ -x $zm ] || [ $zm = *.tar ] || [ $zm = *.gz ] || [ $zm = $tymczasowy ]
then continue
fi
 
echo Dodaję $zm do archiwum.
echo $zm >> $tymczasowy
done
 
tar -T $tymczasowy -cf $1
rm -f $tymczasowy
exit 0
 

Powyższy skrypt pakuje do archiwum o nazwie przekazanej w parametrze wszystkie pliki z bieżącego katalogu, które nie są katalogami, nie mają atrybutu wykonywalności i nie mają rozszerzeń *.tar lub *.gz. Skrypt najpierw zapisuje do pliku tymczasowego nazwy plików, które mają być przetworzone,

a następnie wykonuje polecenie tar z odpowiednim przełącznikiem, by czytał nazwy plików do spakowania z pliku tymczasowego. Ostatnie porównanie w liście OR $zm=$tymczasowy służy do tego, by w pliku tymczasowym nie znalazła się nazwa pliku tymczasowego.

 

Do spisu treści

 

Polecenie 'shift'

Podając parametry do skryptu możemy się do nich odwoływać w skrypcie za pomocą nazw $1, $2, ... , $9. Aby uzyskać dostęp do argumentu 10 i powyżej należy wykonać odpowiednią ilość razy polecenie SHIFT. Pojedyncze wywolanie polecenia przesuwa wszystkie argumenty w ten sposób, że $1

zawiera teraz $2, a $9 zawiera 10 argument. Argument, który uprzednio był w $1 jest tracony. Gdy już wyczerpie się lista argumentów przypisywane są ciągi puste.

 

  • Przykład:
#!/bin/sh 
while [ -n "$1" ]; do
ile=$(($ile+1))
shift
done
 
echo -n Wpisales $ile parametr
 
case $ile in
1 ) echo . ;;
2 | 3 | 4) echo y. ;;
* ) echo ow. ;;
esac

Do spisu treści

 

Polecenie 'set'

Polecenie to ustawia zmienne parametryczne powłoki przez co stają się dostępne w taki sam sposób, jak gdyby były podane jako parametry skryptu.

#!/bin/sh
set raz dwa trzy
echo $1 $3

Wykorzystując dodatkowo zmienną IFS możemy napisac poniższy skrypt, który przetwarza podany mu na wejście plik /etc/passwd wypisując linie zawierające użytkownika i odpowiadający mu katalog domowy. Łącząc go np. z poleceniem grep, możemy wyświetlić tylko tych użytkowników, którzy mają

powłokę bash, np.

  • grep /bin/bash /etc/passwd | nazwa_skryptu
  • Przykład:
#!/bin/sh
IFS=":"
read x
while [ -n "$x" ]; do
set $x
echo $1 $6
read x
done
 
 

 

Do spisu treści

 

Polecenie 'trap'

Polecenie służy do przechwytywania sygnałów wysłanych do procesu skryptu. Listę sygnałów możemy zobaczyć wpisując w powłoce polecenie trap -lSkładnia polecenia: trap Pisząc zamiast polecenia myślnik przypisujemy sygnałowi domyślną akcję.

 

  • Przykład: (nie zapominajmy o odwrotnych cudzysłowach)
#!/bin/sh
trap `echo Nie zamkne sie, hehehe` SIGINT
trap `echo No dobra bede juz grzeczny; trap - SIGINT`
SIGHUP
 
while :
do
echo Naciśnij ^C aby wyjść
sleep 2
done
 

Pierwsze polecenie trap powoduje, że program na wysłanie mu sygnału SIGINT będzie reagował pierwszym komunikatem. Następna linijka mówi, że wysyłając sygnał SIGHUP skrypt również wypisze komunikat, ale też przypisze standardowe działanie dla sygnału SIGINT. Tak więc początkowo naciskając klawisze ^C nie uda nam się zamknąć programu, ale wystarczy wysłać do procesu sygnał SIGHUP, by było to możliwe. Aby wysłać do dowolnego procesu w systemie jakiś sygnał używamy polecenia kill [patrz: man kill]. W naszym przypadku będzie to polecenie kill -SIGHUP PID, gdzie PID to numer identyfikacyjny naszego procesu, sprawdzimy to za pomocą polecenia ps x [patrz: man ps]. PID procesu jest podawany w pierwszej kolumnie, a który to proces znajdziemy po nazwie z ostatniej kolumny.

 

Do spisu treści

 

Funkcje, instrukcja 'return'

  • Składnia:

nazwa_funkcji( ) {

instrukcje

}

lub

function nazwa_funkcji( ) {

instrukcje

}

Parametry do funkcji przekazujemy pisząc w miejscu wywołania nazwę funkcji i listę parametrów. Wewnątrz funkcji do parametrów możemy się dostać tak, jak w bloku głównym do parametrów przekazanych skryptowi, czyli przez zmienne $1, $2, itd. Odpowiednio się zmieniają także zmienne $#, $*, $@. Po zakończeniu działania funkcji parametrom pozycyjne ($#, $*, $@,$1, ..) przywracane są ich pierwotne wartości. Instrukcja 'return' powoduje przerwanie wykonania funkcji i przetwarzanie następnej linijki od miejsca wywołania. Instrukcję 'return' można wykorzystać do tego, by funkcja mogła zwrócić jakąś wartość, jednak nie można umieścić nazwy funkcji po prawej stronie znaku przypisania, tak więc nie można pobrać tej wartości. W praktyce zwraca się jedną z dwu wartości: jeden lub zero, a wynik działania funkcji można sprawdzić w instrukcji 'if'. Aby napisać funkcję, która zwraca jakąś wartość trzeba w tej funkcji użyć nazwy zmiennej, która będzie dostępna w miejscu wywołania funkcji. Poniższy przykład pokazuje jak napisać funkcję zwracającą kwadrat liczby przekazanej w parametrze. Wykorzystujemy tu zmienną pomocniczą kw, której zostanie przypisany kwadrat wyrażenia.

  • Przykład:
$!/bin/sh
kwadrat() {
kw=$(($1*$1))
}
kwadrat 2
echo $kw
 

W kolejnym przykładzie wykorzystujemy instrukcję 'return' do zwrócenia powodzenia danej funkcji, przy czym wartość równa zeru będzie interpretowana jako powodzenie, a różna od zera jako porażka. Zatem jeśli będziemy chcieli napisać funkcję, która ma zostać użyta w instrukcji IF lub w

listach AND i OR, to aby wyrażenie przyjęło wartość prawdy musimy zwrócić zero. Poniższa funkcja oczekuje dwóch parametrów: pliku i znaku mówiącego o prawie dostępu (jeden ze znaków rwx). Gdy użytkownik ma dla danego pliku prawo do operacji przekazanej w parametrze funkcja zwróci zero.

#!/bin/sh
czy_masz_prawa() {
case $2 in
"r") if [ -r $1 ]; then return 0; fi ;;
"w") if [ -w $1 ]; then return 0; fi ;;
"x") if [ -x $1 ]; then return 0; fi ;;
esac
return 1
}
 
if czy_masz_prawa /etc/passwd w; then
echo ziutek::500:500::/home/ziutek:/bin/bash >> /etc/passwd
else echo Brak praw
fi
 

Domyślnie każda zmienna jest globalna. Umieszczając w ciele funkcji przed pierwszym użyciem zmiennej dyrektywę 'local' powodujemy, że jest ona traktowana jako lokalna.

  • Przykład:
$ func1 () { local zmienna=1; }
$ func2 () { zmienna=2; }
$ zmienna=0
$ echo $zmienna
0
$ func1 $ echo $zmienna
0
$ func2 $ echo $zmienna
2

Podając jako parametr nazwę katalogu możemy za pomocą poniższego skryptu zdjąć atrybut wykonywalności dla wszystkich plików danego katalogu i jego podkatalogów. Warto zauważyć, że BASH dopuszcza rekurencję. To samo można zrobić krócej wykorzystując polecenie 'find':

 

find -type f -perm +111 -exec chmod -x {} \;

 

#!/bin/sh
Zdejmij_x() {
for zm in *; do
if [ -f $zm ]; then
chmod –x $zm
fi
 
if [ -d $zm ]; then
cd $zm;
zdejmij_x;
cd ..
fi
done
}
katalog=$PWD
cd $1
zdejmij_x
cd $katalog

Do spisu treści

 

Polecenie 'source'

Gdy wywołujemy skrypt w powłoce dla skryptu tworzone jest nowe środowisko, podobnie jeśli wywołamy w skrypcie jakiś inny skrypt lub program dzieje się podobnie. Polecenie SOURCE pozwala wykonać skrypt w bieżącym kontekście (bez tworzenia nowego środowiska). Ma to między innymi takie zastosowanie jak polecenie include z języka C włączające do pliku programu inny plik. Tak więc możemy oddzielić plik z funkcjami od bloku głównego.

  • Przykład:
#Plik funkcja:
 
czy_masz_prawa() {
 
case $2 in
"r") if [ -r $1 ]; then return 0; fi ;;
"w") if [ -w $1 ]; then return 0; fi ;;
"x") if [ -x $1 ]; then return 0; fi ;;
esac
return 1
 
}
 
 

 

#Plik główny:
 
#!/bin/sh
source funkcja
 
if czy_masz_prawa /etc/passwd w; then
echo ziutek::500:500::/home/ziutek :/bin/bash >> /etc/passwd
else echo Brak praw
fi

Zamiast pisać SOURCE możemy użyć jego krótkiego odpowiednika, czyli pojedynczej kropki, np.:

. funkcja


Do spisu treści

 

Polecenie 'exec'

Polecenie pozwala wywołać program podany w parametrze, o ile jednak zwykłe wywołanie programu tworzy nowe środowisko, to polecenie exec powoduje, że bieżący kontekst procesu zostaje zamazywany przez kontekst programu wywoływanego. Nie można powrócić do skryptu powłoki w

przeciwieństwie do polecenia source, któro nie zmienia kontekstu, lecz podaje polecenia z pliku bieżącej powłoce bez tworzenia nowego środowiska. O ile w przypadku polecenia source parametrem był dowolny plik tekstowy zawierający polecenia do wykonania, to argumentem polecenia exec może być również skompilowany program. Możemy sprawdzić działanie uruchamiając

np. jeden ze skryptów pisząc exec nazwa_skryptu. Po takim wywołaniu i zakończeniu skryptu nie będzie już powłoki, w której go wykonalśmy, gdyż jej kontekst został zastąpiony przez kontekst skryptu.

 

Do spisu treści

 

Polecenie 'wc'

Polecenie to wypisuje na standardowe wyjście ilość linii, słów i bajtów pliku podanego w parametrze. Podając odpowiednie opcje możemy wybrać interesujące nas informacje, które zostaną podane na wyjście.

 

Opcje polecenia 'wc'

-c, --bytes, --chars

wydrukowanie ilości bajtów

-w, --words

wydrukowanie ilości słów

-l, --lines

wydrukowanie ilości linii

 

  • Przykład:
$ dzis=$(date | awk '{print $3}')
$ last | grep root | awk '$5=='$dzis | wc -l
 

Wywołując powyższe polecenia dowiemy ile razy dzisiejszego dnia logował się root.

 

Do spisu treści

 

Polecenie 'cut'

Polecenie dla każdej linii z wejścia wycina określone fragmenty, przy czym dla każdej linii jest to taki sam fragment.

Wejściem mogą być pliki podane w parametrze bądź standardowe wejście.

Opcje polecenia 'cut'

-b, --bytes lista_bajtów

wypisz wyłącznie bajty wyliczone w lista_bajtów

-c, --characters lista_znaków

wypisz wyłącznie znaki wyliczone w lista_znaków (opcja równoważna -b, szczegóły w manualu)

-f, --fields lista_pól

wypisz wyłącznie pola wyliczone w lista_pól

-d, --delimiter delim

separator pól (standardowo tabulator)

-s, --only-delimited

nie drukuj linii nie zawierających separatora pól(ma zastosowanie w przypadku opcji -f)

lista_bajtów, lista_znaków i lista_pól to ciąg liczb bądź zakresów oddzielonych przecinkami, najlepiej zrozumieć to na przykładzie,

  • Przykład:
$ cat /etc/passwd | cut -f 1,6 -d :
$ cat /etc/passwd | cut -f 1,3-5 -d :
$ cat /etc/passwd | cut -f 3- -d :
$ cat /etc/passwd | cut -b -10
 

Domyślnym separatorem pól jest tabulator, więc jeśli na wejście podamy ciąg spacji nie zostanie on uznany za separator. Podobnie jeśli obierzemy za separator spację, tabulator nie będzie separatorem. Problem może rozwiązać polecenie 'col', któro między innymi zamienia tabulatory na spacje. Taki potok wyglądałby następująco:

 

cat plik | col -x | cut -f 1 -d ' '

 

Do spisu treści

 

Polecenie 'tr'

Polecenie tłumaczy lub usuwa znaki ze standardowego wejścia, wynik zapisuje na standardowe wyjście. Musimy do polecenia przekazać jeden lub dwa zbiory znaków. Jeśli będą to dwa zbiory będzie dokonywane tłumaczenie ze zbioru pierwszego na drugi. W przypadku przekazania jednego zbioru dokonuje się w zależności od przekazanych opcji kasowania lub ściskania znaków. Ściskania

znaków można także dokonywać w przypadku dwóch zbiorów. Nie zostały tu wymienione wszystkie kombinacje opcji. Nie zostały też opisane przypadki, kiedy zbiory pierwszy i drugi nie są równej długości lub znaki się powtarzają. Aby sprawdzić jak polecenie reaguje w takim wypadku

zajrzyj do podręcznika systemowego.

 

Opcje polecenia 'tr'

-s, --squeeze-repeats

zastępuje sekwencję powtórzonych znaków zbioru pierwszego pojedynczym wystąpieniem tego znaku

d, --delete

usuwa znaki zawarte w zbiorze pierwszym_

-c, -- complement

jeśli podany przed zbiorem pierwszym pod uwagę jest brane dopełnienie zbioru pierwszego (znaki nie będące w zbiorze)


Postać zbioru znaków

Zbiór znaków może być:

  • listą znaków (można używać znaków poprzedzonych backslashem - należy pamiętać o cudzysłowach, by uniknąć rozwijania tych znaków przez powłokę)
  • zakresem (np. a-z)
  • klasą znaków podawaną w postaci [:nazwa_klasy:], patrz tabelka poniżej

Znaki poprzedzone backslashem

\a

Control-G (bell)

\b

Control-H (backspace)

\f

Control-H (wysuw strony)

\n

Control-J (nowa strona)

\t

Control-I (tabulator)

\v

Control-K (tabulator poziomy)

\ooo

znak o kodzie ósemkowym ooo

\\

backslash

Klasy znaków

alnum

Litery i cyfry

alpha

Litery

blank

Pozioma biała spacja (tabulator, spacja)

cntrl

Znaki kontrolne

digit

Cyfry

graph

Znaki drukowalne (bez spacji)

lower

Małe litery

print

Znaki drukowalne (ze spacją)

punct

Znaki interpunkcyjne

space

Dowolny biały znak

upper

Duże litery

xdigit

Cyfry szestnastkowe

 

 

  • Przykład:
$ tr a-z A-Z
$ tr [:lower:] [:upper:] # obie linijki zamieniają małe znaki na duże.
$ tr -cd [:alnum:] # kasuje wszystkie znaki niealfanumeryczne

 


Przykład:

 

$ for plik in *.HTM; do
> mv $plik `echo ${zm%.HTM} | tr A-Z a-z`.html
> done

Powyższa pętla zamienia wszystkie nazwy plików o rozszerzeniach *.HTM na nazwy o rozszerzeniach *.html zamieniając przy tym wszystkie litery duże na małe.

 

Do spisu treści

 

Grep

grep
- jeden z podstawowych programów wchodzących w skład systemu Unix. Służy do znajdowania w strumieniu wejścia (plik, lub po prostu wpisywany tekst) ciągów znaków pasujących do danego wyrażenia regularnego. Został napisany przez Kena Thompsona.

"grep" jest angielskim akronimem od słów global regular expression print, czyli drukowanie globalnych wyrażeń regularnych.

  • Przykłady zastosowań:
    • wypisanie na standardowym wyjściu linijek pasujących do danego wyrażenia określony tekst: grep "szukany_tekst" plik
    • wypisanie na standardowym wyjściu linijek, nie pasujących do wzorca: grep -v "szukany_tekst" plik


Polecenie "grep" służy do wyszukiwania wzorcu z pliku i przekierowywania. Komenda ta wyświetla linie pasujące lub nie do określonego wzorca.

Uproszczona składnia:

grep [-v] wzorzec [Plik]

-v oznacza negację wzorca (czyli wzorzec nie może wystąpić);
wzorzec - to łańcuch znaków do wyszukiwania, może zawierać wyrażenie regularne;
Plik
- plik/lista plików do przeszukania;

  • Przykłady:
grep 'Ala' plik -znajduje wyraz 'Ala' w pliku;
grep 'A[lg]a' plik -znajduje wyraz 'Ala' lub 'Aga';
grep 'A.a' plik -znajduje wyrazy takie jak 'Ala' 'Aga' itp;
grep '^Ala' plik - znajduje wyraz 'Ala' na początku wersu;
grep 'Go*gle' plik - znajduje wyraz 'Gogle', 'Google' itd;
grep '[0-9]' - znajduje dowolny ciąg znaków z zakresu od 0 do 9;

 


Zadania/sytuacje:
    • Zestawienie tylko nazw pasujących plików:
      grep -l 'main' *.txt

      podaje nazwy wszystkich plików txt z bieżącego katalogu, których zawartość zawiera `main'.

      • Rekurencyjnie przeszukiwanie katalogów:
      grep -r 'hello world' /home/user

      szuka 'hello world' we wszystkich plikach pod katalogiem /home/user.

      • Przeszukiwanie plików jeśli wzorzec zaczyna się od znaków nie standardowych:
      grep -e '--hello world--' *

      szuka wszystkich linii zawierających '--hello world--'. Bez -e , grep wziąłby '--hello world--' jako listę opcji.

      • Szukanie całego ciągu, a nie jego części:
      grep -w 'hello' *

      szuka tylko tych wystąpień ciągu hello, które są całymi wyrazami.

      Można zastosować '\' aby dopasować początek i koniec ciągu:

       grep 'hello\>' *

      wyszukuje tylko ciągi kończące się na hello.

      • Wyświetlenie linii sąsiadujących z pasującymi:
      grep -C 2 'hello' *

      wyświetli 2 linie zawartości przy każdej z dopasowanych linii zawierającej hello.

      • Wyświetlenie dodatkowo na początku linii nazwy pliku zawierającego dany ciąg:
      grep 'username' /etc/passwd /dev/null


      • Filtrowanie samego grep:
      ps -ef | grep '[c]ron'
      Pominięcie nawiasów kwadratowych, dopasowywuje nie tylko linię wyjściową z polecenia ps dotyczącą cron ale i linię wyjściową ps dla samego procesu grep.


      ps -ef | grep 'cron' 

      wyświetli:

      user 3457 2281 0 13:53 pts/1 00:00:00 grep cron
      root 5505 1 0 Feb29 ? 00:00:00 /usr/sbin/cron
       


      Można to także ograniczyć poprzez zastosowanie opcji -v, która oznacza negację wzorca:

      ps -ef |grep 'cron' |grep -v grep
      • Szukanie ciągów zawierających zadany ciąg1 i ciąg2 czyli logiczne AND:
       grep 'hello world' /home/user/*.txt | grep 'zuza,pralka'


      grep wyświetli wszystkie linie zawierające `hello world', oraz/i `zuza,pralka'.

      • Równoczesne przeszukiwanie standardowego wejścia i pliku na przykładzie polecenia cat:
      cat /etc/passwd | grep 'user' - /etc/group


      • Kobinacja polecenia grep z find i xargs.
      find /home/user -name '*.txt' -print | xargs grep 'hello world' /dev/null

      polecenie przeszuka tylko pliki txt pod względem występowania w nich, ciągu 'hello world'

      • Dlaczego grep zgłasza "Binary file matches" - Gdyby grep podał wszystkie pasujące "linie" pliku binarnego, utworzony wynik nie byłby prawdopodobnie do niczego przydatny, a nawet mógłby nabałaganić na ekranie. Zatem GNU grep wyłącza wypisywanie dla plików, które wyglądają na binarne. Możemy zmusić go do wypisywania dopasowanych linii również dla takich plików stosując opcję '-a' lub '--binary-files=text'. Chcąc się pozbyć komunikatów "Binary file matches" ("Plik binarny pasuje do wzorca") należy skorzystać z opcji '-I' lub `--binary-files=without-match'.


      • Dlaczego `grep -lv' nie wypisuje nazw plików niepasujących? `grep -lv' wypisuje nazwy wszystkich plików zawierających co najmniej jedną niepasującą linię. Do uzyskania listy nazw wszystkich plików nie zawierających żadnych pasujących linii, należy użyć opcji `-L' lub `--files-without-match'.
      • Przydatne linki:

      Więcej na temat grep oraz tłumaczenie dokumentacji man:
      http://ultra.ap.krakow.pl/~bar/GREP/grep_toc.html

       

      Do spisu treści

       

      Sed

      sed (ang. Stream EDitor – edytor strumieniowy) – program służący do przetwarzania plików tekstowych.

      sed jest filtrem – pobiera dane w postaci wierszy tekstu ze standardowego wejścia, przetwarza je zgodnie z poleceniami podanymi w wierszu poleceń lub zapisanymi w pliku i przesyła wyniki operacji na standardowe wyjście. Cechą charakterystyczną seda jest to, że wykonuje on na danym wierszu wszystkie polecenia, jakie są do wykonania. Ponieważ przetwarzanie odbywa się wiersz po wierszu, sed nie ma praktycznie żadnych ograniczeń na wielkość przetwarzanego pliku.
      Sed nadaje się szczególnie do przetwarzania plików o pewnej strukturze. Napisany został pierwotnie przez Lee E. McMahona dla systemu UNIX w roku 1973, w chwili obecnej dostępny jest praktycznie dla każdego systemu operacyjnego, który dysponuje wierszem poleceń.
      Zestaw poleceń programu sed wzorowany jest na poleceniach programu ed i większość z nich działa podobnie, jeśli uwzględni się specyfikę seda. Na przykład, polecenie 25d działa w sedzie następująco: sprawdza, czy bieżący wiersz jest 25 wierszem przetwarzanego pliku i jeśli tak, to nie kieruje go na wyjście ("usuwa" go), a jeśli nie, wiersz pojawi się na wyjściu. Jednak nie wszystkie polecenia eda mogły zostać zaimplementowane, w szczególności te, które odpowiedzialne są za kopiowanie lub przenoszenie tekstu. Zamiast tego, sed dysponuje buforem, który pozwala przechować wybrane wiersze i zestawem poleceń do manipulacji nimi. Na przykład, polecenie eda 25t76 (skopiuj wiersz 25 do 76) można zrealizować w sedzie jako dwa polecenia: 25h; 76g – przechowaj wiersz 25 w buforze i wstaw po napotkaniu wiersza 76.
      • Oto typowy przykład wywołania seda:

      sed -e 's/dobry/zły/g' plik_wejściowy > plik_wyjściowy

      s oznacza zastępowanie, g globalne, w całym wierszu. Po pierwszym ukośniku pojawia się wyrażenie regularne, opisujące tekst, który ma być wyszukany, po drugim wyrażenie, które ma zastąpić wyszukany tekst. Polecenie zastępowania jest najczęściej wykonywanym poleceniem seda.

      • Przykład wywołania seda z dołączonym zewnętrznym plikiem poleceń polecenia.sed:

      sed -f polecenia.sed plik_wejściowy > plik_wyjściowy

      Następujące wywołanie usuwa z pliku wszystkie puste wiersze, lub te, które zawierają wyłącznie spacje:

      sed -e '/^\ *$/d' inputFileName 

       

      • Przykład ten wykorzystuje kilka metaznaków używanych w wyrażeniach regularnych seda:
        • ^ – pasuje do początku wiersza
        • $ – pasuje do końca wiersza
        • . – pasuje do dowolnego znaku
        • * – pasuje do dowolnej (również zerowej) liczby wystąpień poprzedzającego znaku
        • [ ] – pasuje do dowolnego znaku wewnątrz nawiasów [ ]

      De facto sed jest prostym językiem programowania i mimo że nie pozwala na korzystanie z żadnych zmiennych, dopuszcza jedynie proste instrukcje skoku, to jest językiem zupełnym w sensie Turinga.

      sed wyewoluował z grepa, programu wyszukującego frazy tekstowe w plikach i był jednym z pierwszych programów unixowych pozwalających na edycję plików z wiersza poleceń, a jego pojawienie się stanowiło impuls do powszechnego używania wyrażeń regularnych. Podobny w idei działania awk może być traktowany jako następca seda. Wraz z awkiem, sed uważany jest za prekursora języka Perl. W szczególności, s/// jest poleceniem Perla.

      Mimo sędziwego wieku sed nadal jest używany i rozwijany ze względu na szybkość działania. W specyficznych operacjach bije na głowę zarówno AWKa jak i Perla. Ciekawym rozwinięciem seda jest GNU sed pozwalający na bezpośrednią zmianę przetwarzanego pliku i Super-sed, którego składnia jest zgodna ze składnią Perla.

      źródło: http://pl.wikipedia.org/wiki/Sed_(program)

      • Przydatne linki:

      przykłady użycia: http://www.gentoo.org/doc/pl/articles/l-sed1.xml

      skrypty sed: http://sed.sourceforge.net/

      "jednolinijkowce": http://sed.sourceforge.net/sed1line.txt


      Do spisu treści

       

      Awk

      AWK jest interpretowanym językiem programowania, którego główną funkcją jest wyszukiwanie i przetwarzanie wzorców. Jest także nazwą programu początkowo dostępnego dla systemów operacyjnych będących pochodnymi UNIX-a, obecnie także na inne platformy. Nazwa języka pochodzi od pierwszych liter nazwisk jego autorów Alfreda V. Aho, Petera Weinbergera i Briana Kernighana i czasami jest zapisywana małymi literami oraz odczytywana jako jedno słowo awk.

      Definicja języka AWK jest zawarta w POSIX 1003.2 Command Language And Utilities Standard. Wersja ta jest z kolei oparta na opisie z The AWK Programming Language, napisanym przez Aho, Weinbergera i Kernighana, z dodatkowymi właściwościami, zdefiniowanymi w wersji awk z SysVR4.

      W wierszu poleceń podaje się opcje dla awk, tekst programu (jeśli nie podano go poprzez opcję -f lub --file) i wartości, które mają być udostępnione w predefiniowanych zmiennych ARGC i ARGV.

      Źródło: http://pl.wikipedia.org/wiki/AWK

      • Przykład wywołania:
      awk -f ...
      • najpopularniejszym użyciem awk jest polecenie:

      awk '{ print $1 }' ...

      powoduje to wypisanie pierwszego pola z każdego rekordu: np. pierwszego wyrazu.
      • Przydatne linki:

      Tutorial awk: http://sokrates.mimuw.edu.pl/~sebek/awk.html

       

      Do spisu treści

       

      Magia polecenia find

      Find - program służący do przeszukiwania systemu.

      Składnia:

      find katalog_startowy cecha akcja

      np:

      find /home/user/ -name nazwa_pliku.txt
      find /home/user -name "*.txt" -print

       

      - co wyszuka nam w katalogu /home/user plik nazwa_pliku.txt lub drugi przykład wszystkie pliki *.txt

      • cechy do określenia plików:
      -name pattern - nazwa pliku okrełona przy pomocy danego wzorca;
      -atime $n$ - do pliku zaglądano $n$ dni wcześniej;
      -ctime $n$ - status pliku zmieniono $n$ dni wcześniej;
      -mtime $n$ - zawartość pliku zmieniono $n$ dni wcześniej;
      -user username - plik należy do danego użytkownika;
      -group gname - dana grupa pliku;
      -perm przywileje - pliki o danych przywilejach;
      -local - plik na lokalnym systemie plików;
      -size n[c] - dany rozmiar pliku;
      -type c - dany typ pliku ( b, c, d, D, f, l, p, lub s).
       b – blokowy (buforowany) plik specjalny
      c – znakowy (niebuforowany) plik specjalny
      d – katalog
      p – łącze nazwane (FIFO)
      f – zwykły plik
      l – dowiązanie symboliczne
      s – gniazdo
      W okresleniu cechy można stosować oznaczenia "+n'' lub "-n'': pierwsze znaczy "więcej, niż... '', drugie "mniej, niż... '' np. -atime +15 oznacza pliki otwierane przed więcej, niż 15-oma dniami.

      • Typowe akcje:

      -print - po prostu drukuje nazwę pliku;
      -exec polecenie - wykonanie dla każdego ze znalezionych plików danego polecenia;
      -ok polecenie - jak wyżej ale trzeba potwierdzić przed każdym wykonaniem.

      • Czasem lepiej jest korzystać z przekierowania wyników poszukiwań do polecenia xargs niż z akcji exec:
      zamiast:
      find / -name core -exec rm -f {} \;

      wersja z xargs
      find / -name core -print | xargs rm -f

       

      Przykłady zastosowań:

      • przeszukanie katalogu /home/user/muza pod kątem wystąpienia w nazwie pliku ciągu shazza (-iname pomija rozróżnianie wielkości znaków).
      find /home/user/muza -iname shazza
      • przeszuka katalog i wyświetli nazwy plików, które nie mają w sobie nazwy 'shazza'
      find /home/user/muza ! -name 'shazza'

       

      • szukanie w aktualnym katalogu i wyświetlenie wszystkich plików których data ustawiona jest na Dec 21
      find `pwd` -exec ls -l '{}' \; | grep "Dec 21"

       

      • szukanie podkatalogów w katalogu /katalog należących do użytkownika osoba
      find /katalog/ -user osoba -type d

       

      • wyszukaj i skasuj wszystkie pliki z katalogu /tmp należące do usera nazwa_usera
      find /tmp -user nazwa_usera -exec rm -rf {} \;

       

      • Szukanie w bieżącym katalogu plików o rozmiarach przekraczających 10 MB z wyświetleniem szczegułów (ls -l):
      find . -size +10485760c -exec ls -l {} \;
      • szukanie ciągu, gdy nie wiadomo w jakim pliku jest ciąg i w jakim katalogu znajduje się plik:
      find /home/user/ -name "*.txt" -print | xargs grep "szukany_ciag"

      • szukanie plików, w różnych katalogach - najpierwsz pszeszuka usr, home i na koncu tmp:
      find /usr /home /tmp -name "*.jar

       

      • pominiecie komunikatów o błędach jeśli nie mamy prawa dostepu do któregoś z katalogów:
      find /usr /home /tmp -name "*.jar" 2>/dev/null 

       

      • Możemy także szukać plików które były modifikowane albo otwierane pod względem opcji -newer, -anewer, and –cnewer. Jest to podobne do -mtime, -atime, and –ctime.

      • -newer wskazuje na pliki, których zawartość nie była modyfikowana ostatnio
      • -anewer wskazuje na pliki, które były odczytywane ostatnio
      • -cnewer wskazuje na pliki, których status zmienił się ostatnio

      - Aby odnaleźć pliki w katalogu domowym /home które były jakkolwiek edytowane od ostatniego pliku tar:

      find ~ -newer backup.tar.gz 

       

      • szukanie plików po prawach dostępu do plików:
      find . -type f -perm a=rwx -exec ls -l {} \; 
       
      #albo
       
      find . -type f -perm 777 -exec ls -l {} \;
      find . -type f -perm -ug=rw -exec ls -l {} \; 2>/dev/null
       
      #albo
       
      find . -type f -perm -220 -exec ls -l {} \; 2>/dev/null
      find . -type f -perm /ug=rw -exec ls -l {} \; 2>/dev/null
      find . -type f -perm /220 -exec ls -l {} \; 2>/dev/null

       

      • Aby wyszukać wszystkie pliki w systemie które mogą być edytowane przez wszystkich użytkowników:
      find / -wholename '/proc' -prune -o -type f -perm -0002 -exec ls -l {} \; 

       

      • Inne przydatne komendy find:
      #Szukanie plików po użytkowniku, grupie:
       
      [root] $ find / -type f -user username -exec ls -ls {} \;
      [root] $ find / -type f -group users
       
      find / -type d -gid 100

      wylistuje pliki które nie mają odniesienia do /etc/passwd i /etc/group w uzytkowniku i grupie
      find / -nouser -o -nogroup 
      pokaz pliki z prawami SID oraz GID
      find / \( -perm -2000 -o -perm -4000 \) -ls
      167901 12 -rwsr-xr-x 1 root root 9340 Jun 16 2006 /usr/bin/rsh
      167334 12 -rwxr-sr-x 1 root tty 10532 May 4 2007 /usr/bin/wall




      Welcome to the real worldLaughing
      Przykłady:
        • Wyświetl wszystkie pliki jpg w głąb do dwóch poziomów głównej struktury katalogu domowego:
        find $HOME -maxdepth 2 -name \*jpg -print -exec xv {} \;
        find $HOME -maxdepth 2 -name '*jpg' -print -exec xv {} +
        find $HOME -maxdepth 2 -name '*jpg' -print0 | xargs -0 xv
        • zadanie crontab, nadające uprawnienia wszystkim plikom i katalogom do czytania i pisania dla wszystkich w zadanych katalogach:
        find /home/user -type f -exec chmod a+wr {} \;
        find /home/user -type d -exec chmod 777 {} \;
        • zadanie crontab wymuszające ustawienie poprawnych uprawnień dla właściciela i grupy dla poszczególnych plików:
        find /home/user \( -name '[p,u]*' -a -type f -a ! -perm 664 \) -exec chmod 664 {} \;
        find /home/user \( -name 'd*' -a -type f -a ! -perm 666 \) -exec chmod 666 {} \;
        find /home/user \( -type f -a ! -user username \) -exec chown username {} \;
        find /home/user \( -type f -a ! -group groupname \) -exec chgrp programs {} \;
        • zadanie: kasowanie starszych niż 30 dni logów i rejestrację informacji o skasowanych plikach:
        find /directory/log -mtime +30 -print -exec rm -f {} \; >> del_files.log 2> /dev/null
         
        #znajdź dzisiejsze logi i skopiuje je do zadanego katalogu
         
        find logs/ -type f -mtime -1 -exec cp -v {} /home/user/backup_logs \;
        • funkcja: kasuje stare pliki tymczasowe o danych definicjach nazw z rejestracją informacji o skasowanych plikach
        find / -name core -type f -fstype xfs -print -exec rm -f {} \; >> del_files 2> /dev/null
        find /var/tmp -mtime +1 -name '*ala*' -print -exec rm -f {} \; >> del_files 2 > /dev/null
        find /var/tmp -mtime +1 -name 'string*' -print -exec rm -f {} \; >> del_files 2 > /dev/null
        find /var/tmp -mtime +7 -print -exec rm -f {} \; >> del_files 2 > /dev/null
        • Przeszukanie katalogu /var tylko raz, a następnie wylistuje wszystkie pliki z uprawnieniami SUID do pliku suid.txt oraz wszystkie pliki duże pliki (większe niż 100 MB) z listingiem do pliku big.txt (przykład zaciągnięty z manuala programu find):
        find /var \( -perm +4000 -fprintf /root/suid.txt '%#m %u %p\n' \) , \
        \( -size +100M -fprintf /root/big.txt '%-10s %p\n' \)

         

        Magia find + xargs:

        • xargs znacznie poprawia szybkość i wydajność

        - druga linia wykonuje się szybciej niż pierwsza dla dużej ilości plików

         

        find / -name core -exec rm -f {} \;
        rm -f $(find / -name core -print)

        - Innymi słowy wywołując jednokrotnie polecenie "rm" włączając wszystkie nazwy plików, jest szybsze niż wielokrotne wywoływanie polecenia "rm" osobno dla każdego pliku.

        - Jednakże drugie polecenie może się nie powieść, kiedy liczba plików jest bardzo duża i przekracza maksymalną liczbę znaków dozwolonych w jednym poleceniu (komendzie)

        - "xargs" połączy wyjście komendy z pierwszej linii polecenia find i wykona się wielokrotnie z wielokrotnymi argumentami jeżeli będzie to konieczne aby zapobiec przekroczeniu maksymalnej ilości dostępnych znaków w jednej komendzie.

        find / -name core -print | xargs rm -f

        - wykonując proste polecenia można łatwo zobaczyć siłę programu xargs:

        find $HOME -maxdepth 2 -name \*.jpg -exec echo {} \;
        find $HOME -maxdepth 2 -name \*.jpg | xargs echo


        Potęga opcji zero!

        - Druga komenda się nie powiedzie jeżeli którekolwiek z plików będzie zawierało spację lub inne specjalne znaki:

        find $HOME -maxdepth 2 -name \*.jpg -exec ls {} \;
        find $HOME -maxdepth 2 -name \*.jpg | xargs ls
         

        - wyeliminowanie pustych pól z nazw plików rozwiązuje problem:
        find $HOME -maxdepth 2 -name \*.jpg -print0 | xargs -0 ls

         

        • Uwaga: dobrym sposobem na testowanie komend jest używanie "-exec echo", zanim wydamy prawdziwą komendę a w szczególności taką która ma kasować jakiekolwiek pliki w systemie ( -exec rm -rf {} ).

        Do spisu treści


        blog comments powered by Disqus
         
        Banner