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
Hello World i wykonanie skryptuTradycyjnie 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:
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/hellish
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.
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
Echo jest poleceniem wyswietlajacym na ekranie swoje argumenty.
#!/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 (fr 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 podwoic, 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"
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.
(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 [ ]
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 exitPolecenie 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:
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.
#!/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 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…
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 [email protected] 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
ZmienneW 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 $
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.
$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 $
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 biezacej powloki – nazwa wykonywanego skryptu – liczba przekazanych parametrów – lista parametrów porozdzielanych pierwszym znakiem ze zmiennej $IFS, przyklad poniezej – lista parametrów porozdzielanych spacjami – poszczególne parametry w kolejnosci podanej przy uruchamianiu skryptu |
Przyklad:
#!/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 $
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 ( ` ` ) 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.
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
Rozwiniecia parametryczneZaló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 rozwiniecia parametryczne |
|
${parametr:-slowo} |
wartoscia jest wartosc zmiennej parametr jesli przeciwnym wypadku wartoscia jest slowo (zmienna parametr sie nie zmienia) |
${parametr:=slowo |
wartoscia wyrazenia jest wartosc zmiennej parametr jesli jest ona zdefiniowana i nie jest pusta, w przeciwnym wypadku wartoscia |
${parametr:?slowo} |
wartoscia wyrazenia jest wartosc parametru, jesli |
${parametr:+slowo} |
jesli parametr jest niezdefiniowany badz null nic |
${#parametr} |
zwraca dlugosc zmiennej parametr w znakach |
${parametr#slowo} |
zwraca wartosc parametru po usunieciu z niego |
${parametr##slowo} |
zwraca wartosc parametru po usunieciu z niego |
${parametr%slowo} |
zwraca wartosc parametru po usunieciu z niego |
${parametr%%slowo} |
zwraca wartosc parametru po usunieciu z niego |
Przyklad:
!/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 nastepujacych linii: /etc/lilo.conf lilo.conf etc/lilo.conf /etc
Przyklad:
#!/bin/sh line=`grep ^root /etc/passwd` echo Shell roota: ${line##*:}
Polecenie to ma wiele opcji i jest czesto wykorzystywane w skryptach do realizowania róznych warunków logicznych, gdyz zawsze zwraca wartosc logiczna.
Posiada dwa rodzaje skladni, np.:
$ if test -f /etc/passwd; then > echo "plik passwd istnieje w /etc" > fi
jest równowazne wykonaniu:
$ if [ -f /etc/passwd ]; then > echo "plik passwd istnieje w /etc" > fi
Nalezy pamietac o istotnym szczególe, mianowicie o pozostawieniu przynajmniej po jednej spacji po nawiasie otwierajacym i przed zamykajacym.
Porównanie ciagów |
|
lancuch |
ciag nie jest pusty |
lancuch1 = lancuch2, lancuch == lancuch2 |
ciagi sa jednakowe |
lancuch1 != lancuch2 |
ciagi sa rózne |
-n lancuch |
ciag nie jest pusty |
z lancuch |
ciag jest pusty |
Porównania arytmetyczne |
|
wyr1 -eq wyr2 |
wyrazenia sa równe |
wyr1 -ne wyr2 |
wyrazenia sa rózne |
wyr1 -gt wyr2 wyr1 |
jest wieksze od wyr2 |
wyr1 -ge wyr2 wyr1 |
jest wieksze 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 |
wyrazenia 1 i 2 sa prawdziwe (AND) |
wyr1 -o wyr2 |
jedno z wyrazen jest prawdziwe (OR) |
! wyr |
wyrazenie jest zerowe |
Sprawdzenia plików |
|
-a plik |
plik istnieje |
-b plik |
plik jest urzadzeniem blokowym |
-c plik |
plik jest urzadzeniem 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 wlasciciela = EGID |
-k plik |
plik z ustawionym bitem sticky |
-L plik |
plik jest linkiem symbolicznym |
-O plik |
plik, którego UID wlasciciela = EUID |
-p plik |
plik jest laczem nazwanym (PIPE) |
-r plik |
plik jest odczytywalny |
-s plik |
plik ma niezerowa wielkosc |
-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 maja ten sam numer urzadzenia oraz i-wezla |
plik1 -nt plik2 |
plik1 jest mlodszy niz plik2 |
plik2 -ot plik2 |
plik1 jest starszy niz plik2 |
Inne |
|
-o nazwa opcji |
opcja powlokinazwa opcjijest wlaczona |
Jest jeden szczegól o którym warto pamietac uzywajac opcji -G i -O. Mozna nadac 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ównosci i róznosci w warunkach. Moze byc kilka niejasnosci odnosnie niektórych warunków dotyczacych sprawdzania plików, ale nie to jest przedmiotem tego kursu i nie zostana tu wyjasnione. W wiekszosci wypadków wystarczy znac opcje z literami: d, f, r, s, w, x. Role spójników logicznych AND i OR pelnia odpowiednio operatory: -a i -o, np. [ wyr1 -a wyr2 -o wyr3 ].
Polecenie ‘test’ jest poleceniem zewnetrznym dla powloki. ‘[‘ jest linkiem symbolicznym do polecenia test. Piszac wiec [ wyrazenie ] zostaje wywolane polecenie test z dodatkowym argumentem ‘]’. Istnieje jednak wewnetrzna konstrukcja w BASH’u, która pozwala obliczac wyrazenia logiczne.
[[ wyrazenie ]]
Przyjmuje ona taki sam zestaw opcji oprócz spójników logicznych AND i OR, którymi sa tu odpowiednio && i ||
Jak mówi podrecznik systemowy, polecenie expr wykonuje obliczenie wyrazenia i zapisuje je na standardowe wyjscie. Jako, ze jest to polecenie zewnetrzne dla powloki wykorzystuje sie je wpisujac w odwrotne apostrofy, badz w równowazna im konstrukcje $(polecenie).
Przyklad:
$ ile=5 $ ile=`expr $ile + 5` $ ile=$(expr $ile + 5) $ echo $ile 15
Polecenie przyjmuje w parametrze ciag operandów i operatorów, które musza byc porozdzielane spacjami.
Operandy moga byc liczbami badz ciagami 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, mnozenie, dzielenie calkowite, dzielenie modulo) |
operatory porównania (operatory: ‘=’ i ‘==’ sa równowazne) | |
: | dokonuje porównania wzorców, oba argumenty rzutowane sa na napisy przy czym drugi z argumentów moze byc wyrazeniem regularnym w postaci akceptowalnej przez GREP’a. Jesli wzorce pasuja do sieie zwracana jest dlugosc napisu, jesli nie, zwracane jest zero. Dodatkowo jesli w drugim argumencie umieszczona zostanie jednapara nawiasów ‘(‘ i ‘)’, to w przypadku pasowania wzorców zostanie zwrócony napis zawarty miedzy tymi nawiasami lub napis pusty w przypadku przeciwnym. |
rozpoznawane slowa kluczowe | |
match napis wyr_ regularne |
to samo co ‘napis : wyr regularne’ |
substr napis pozycja dlugosc |
zwraca podnapis z podanego napisu o podanej dlugosci i zaczynajacy sie od podanej pozycji |
index napis znaki |
zwraca pozycje wystapienia tego znaku ze zbioru znaków bedacego drugim argumentem, którego zajmuje najnizsza pozycje w napisie |
length napis | zwraca dlugosc napisu |
Przyklady:
$ 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 .*' # wyrazenie regularne 11 $ expr "$napis" : 'Ala ma (kot)a' kot
Jest to instrukcja warunkowa, z która kazdy, kto programowal w jakims jezyku programowania musial sie zetknac.
Skladnia polecenia:
if warunek
then
instrukcje
else
instrukcje
fi
Jako ze jestesmy przyzwyczajeni do pisania else w tej samej linii co if, mozemy tak dalej robic, tylko musimy oddzielic instrukcje if warunek od then srednikiem, gdyz inaczej powloka traktuje then jako dokonczenie warunku.
Przyklad:
$ if [ -f /etc/passwd ]; then echo plik_istnieje ; else echo Ups; fi
W przypadku zlozonych warunków slowa else if stojace obok siebie mozna zlaczyc w slowo elif.
Ponizszy skrypt drukuje najwieksza 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 ponizsze polecenia, niech imie bedzie zmienna niezainicjowana.
$ if [ $imie = "franek" ] > then echo Cze_franek > fi [: =: unary operator expected
Ostatni komunikat bledu spowodowany jest tym, ze zmienna imie jest niezainicjowana, wobec czego warunek w nawiasach staje sie warunkiem [ = “franek” ]. Czyli brakuje jednego parametru. Problem rozwiaze nastepujacy zapis: [ “$imie” = “franek” ], a warunek staje sie warunkiem [ “” = “franek” ].
Skladnia
instrukcja1 && instrukcja2 && instrukcja3 && instrukcja4 …
Wykonywane sa instrukcje po kolei az do momentu okreslenia wyniku calosci wyrazenia, czyli jesli np. instrukcja1 zwróci FALSE, to instrukcja2 sie juz nie wykona, a calosc wyrazenia przyjmie wartosc FALSE. Aby otrzymac TRUE, wszystkie sposród instrukcji musza zwrócic TRUE, w tym wypadku wszystkie one zostana wykonane. Zamiast instrukcji moze wystapic dowolne wyrazenie, wtedy zamiast wykonywania instrukcji zostanie obliczona wartosc tego wyrazenia. Calosc mozna traktowac jako ciag iloczynów logicznych przetwarzany od lewej do prawej, w którym instrukcje sa wykonywane dopóki wartosc wyrazenia nie jest jeszcze okreslona.
Skladnia:
instrukcja1 || instrukcja2 || instrukcja3 || instrukcja4 …
Analogicznie jak w przypadku listy AND instrukcje sa wykonywane do momentu okreslenia calosci wyrazenia, tylko w tym przypadku jest odwrotnie, mianowicie jesli dowolna z instrukcji przyjmie wartosc TRUE, to wartosc wyrazenia bedzie okreslona jako TRUE i dalsze instrukcje sie nie wykonaja. Zwrócenie przez instrukcje FALSE powoduje dalsze przetwarzanie wyrazenia. Aby otrzymac FALSE, wszystkie instrukcje musza zwrócic FALSE.
Wyrazenie mozna traktowac jako ciag sum logicznych. Mozna laczyc ze soba listy AND i OR, by uzyskac bardziej skomplikowane warunki. Zaden z operatorów && i || nie ma wyzszego priorytetu od drugiego. Calosc wyrazenia jest wykonywana sekwencyjnie od lewej do prawej, jesli chcemy to zmienic mozna uzyc nawiasów zwyklych.
Przyklad
$ [ -f /etc/passwd ] && echo Ufff || echo Ups Ups Laughing
Przyklad:
#!/bin/sh $1 -ge $2 ] && ( [ $1 -ge $3 ] && echo $1 || echo $3) || ([ $2 -ge $3 ] && echo $2) || echo $3
Powyzszy skrypt wyswietla na ekran najwiekszy z 3 podanych mu parametrów. Nowy element pojawil sie w 2 wierszu w przykladzie 2 na koncu linii – backslash. Postawienie znaku backslash na koncu wiersza informuje powloke, ze dana linijka jest kontynuowana w nastepnym wierszu (normalnie nastepny wiersz to nastepna instrukcja). Dzieki temu nie musimy pisac dlugich wierszy, które przeszkadzaja w wygodnym edytowaniu i ogladaniu pliku (nie wszystkie edytory obsluguja automatyczne zawijanie).
Wszedzie tam, gdzie musimy uzyc pojedynczej instrukcji, mozemy zastosowac blok instrukcji, czyli ciag instrukcji ujety w nawiasy klamrowe lub zwykle.
{ ciag polecen; }
lub
(ciag polecen)
W przypadku nawiasów klamrowych polecenia sa wykonywane w biezacej powloce i srodowisku. Wartoscia takiego bloku jest wartosc ostatniej instrukcji. Dla polecen w nawiasach zwyklych tworzona jest nowa powloka. Wartoscia zwracana jest kod ostatniej instrukcji badz wartosc zwrócona przez komende ‘exit’.
Przyklad:
$ if true && { false;false;true } > then echo TRUE > fi TRUE $ if true && (false;false;exit 0) > then echo TRUE > fi TRUE
true i false sa poleceniami zwracajacymi odpowiednio prawde i falsz. Dodatkowo false jest czesto wpisywane w /etc/passwd w ostatniej kolumnie, by uniemozliwic uzytkownikowi wejscie na shella. Zamiast polecenia true moze tez wystapic : (pojedynczy dwukropek), któro jest poleceniem pustym zwracajacym prawde, np.
$ while : > do echo -e \a > done
case zmienna in
ciag_wzorca [ | ciag_wzorca ] … ) ciag_instrukcji ;;
ciag_wzorca [ | ciag_wzorca ] … ) ciag_instrukcji ;;
…
esac
Polecenie to dziala w ten sposob, ze dopasowuje zmienna po kolei do wzorcow i po udanym dopasowaniu wykonuje ciag instrukcji przyporzadkowany temu wzorcowi. Jesli zmienna pasuje do kilku wzorcow, wykona sie tylko pierwszy. W przypadku, gdy nie pasuje do zadnego wzorca nic sie nie wykona. Aby wykonala sie jakas czynnosc domyslna stosuje sie znak * jako wzorzec. Wzorzec ten pasuje do kazdej wartosci zmiennej, nalezy wiec pamietac, by wpisac go na koncu. Przy stosowaniu polecenia nalezy sie kierowac zasada, by bardziej ogólne wzorce umieszczac dalej. Najlepiej jednak zobaczyc to na przykladzie,
Przyklad:
#!/bin/sh echo Czy chcesz kontynuowac? read x case $x in "tak" | "TAK" | "T" | "t" ) echo Wpisales tak;; "nie" | "NIE" | "N" | "n" ) echo Wpisales nie;; * ) echo Nie wiem co wpisales;; esac
Skracajac i uogólniajac powyzsze warunki otrzymamy ponizszy skrypt. Wtedy do pierwszego wzorca pasuje litera T lub t lub napis “tak” w którym dowolna z jego liter moze byc mala lub duza.
#!/bin/sh echo Czy chcesz kontynuowac? read x case $x in [Tt][Aa][Kk] | [Tt] ) echo Wpisales tak;; [Nn][Ii][Ee] | [Nn] ) echo Wpisales nie;; * ) echo Nie wiem co wpisales;; esac
for zmienna in zbiór_wartosci do
instrukcje
done
Petla FOR dziala w ten sposób, ze dla kazdego elementu ze zbioru wartosci przypisuje go do zmiennej i wykonuje instrukcje zawarte wewnatrz petli.
Zbiór wartosci nie musi byc podany jawnie, moze byc rozwiniety przez powloke, np.:
Przyklad:
#!/bin/sh for zm in * do if [ -u $zm ] then echo $zm fi done
W tym wypadku powloka rozwija znak * w liste plików z biezacego katalogu. Powyzszy skrypt drukuje na ekranie pliki, które maja ustawiony bit SUID. Ponizszy przyklad pokazuje jak wyslac do wszystkich uzytkowników systemu posiadajacych konta shellowe z powloka /bin/bash. Pamietajmy o odwróconych cudzyslowach.
#!/bin/sh for user in `cat /etc/passwd | grep /bin/bash | cut -d : -f -1` do echo "Czesc mam do sprzedania fortepian" | mail -s "Spam" $user done
while warunek
do
instrukcje
done
Warunek sprawdzany jest przed wywolaniem instrukcji. Instrukcje beda wykonywane dopóki warunek jest prawdziwy.
Przyklad:
#!/bin/sh i=1 while [ $i -le 5 ]; do echo "$i) Opcja $i" i=$(($i+1)) done
until warunek
do
instrukcje
done
Petla ta jest podobna do petli WHILE z ta róznica, ze instrukcje sa wykonywane dopóty warunek jest falszywy. Jesli warunek staje sie prawdziwy petla jest przerywana.
Przyklad:
#!/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 zalogowal sie root. Jesli tak, to powiadamia nas i konczy dzialanie. Jesli w momencie uruchomienia skryptu root jest juz w systemie, instrukcje w petli UNTIL nie wykonaja sie ani razu.
select zmienna [ in zbiór_wartosci ]
do
instrukcje
done
Zbiór wartosci jest wyswietlany na standardowym wyjsciu, kazda pozycje poprzedza numer. Jesli pominiemy in zbiór_wartosci wyswietlone zostana parametry pozycyjne (parametry przekazane do skryptu badz parametry przekazane funkcji). Wyswietlany jest nastepnie znak zachety systemu (ze zmiennej PS3) i powloka oczekuje na wprowadzenie numeru. Jesli wprowadzimy poprawny numer zmienna z polecenia otrzyma wartosc odpowiadajaca temu numerowi, jesli nie jest to numer, badz numer jest bledny zmienna ta otrzyma wartosc NULL. Nastepnie wykonywane sa instrukcje wewnatrz bloku. Potem wszystko zaczyna sie od poczatku. Aby wyjsc z petli nalezy wsród instrukcji wstawic polecenie break lub return lub tez wprowadzic znak EOF. Dodatkowo wprowadzona przez nas linia jest pamietana w zmiennej REPLY.
Przyklad:
$ select plik in * > do > echo Wpisana linia: $REPLY > Wybrales $plik > break > done
Oba polecenia sluza do wczesniejszego wyjscia z aktualnego przebiegu petli, z ta róznica, ze po wykonaniu BREAK wykonywanie petli konczy sie calkowicie podczas, gdy po wykonaniu CONTINUE pomijane sa polecenia za CONTINUE i wykonywany jest nastepny przebieg petli. Najlepiej zobaczyc to na przykladzie.
Przyklad:
#!/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 Dodaje $zm do archiwum. echo $zm >> $tymczasowy done tar -T $tymczasowy -cf $1 rm -f $tymczasowy exit 0
Powyzszy skrypt pakuje do archiwum o nazwie przekazanej w parametrze wszystkie pliki z biezacego katalogu, które nie sa katalogami, nie maja atrybutu wykonywalnosci i nie maja rozszerzen *.tar lub *.gz. Skrypt najpierw zapisuje do pliku tymczasowego nazwy plików, które maja byc przetworzone, a nastepnie wykonuje polecenie tar z odpowiednim przelacznikiem, by czytal nazwy plików do spakowania z pliku tymczasowego. Ostatnie porównanie w liscie OR $zm=$tymczasowy sluzy do tego, by w pliku tymczasowym nie znalazla sie nazwa pliku tymczasowego.
Podajac parametry do skryptu mozemy sie do nich odwolywac w skrypcie za pomoca nazw $1, $2, … , $9. Aby uzyskac dostep do argumentu 10 i powyzej nalezy wykonac odpowiednia ilosc razy polecenie SHIFT. Pojedyncze wywolanie polecenia przesuwa wszystkie argumenty w ten sposób, ze $1
zawiera teraz $2, a $9 zawiera 10 argument. Argument, który uprzednio byl w $1 jest tracony. Gdy juz wyczerpie sie lista argumentów przypisywane sa ciagi puste.
Przyklad:
#!/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
Polecenie to ustawia zmienne parametryczne powloki przez co staja sie dostepne w taki sam sposób, jak gdyby byly podane jako parametry skryptu.
#!/bin/sh set raz dwa trzy echo $1 $3
Wykorzystujac dodatkowo zmienna IFS mozemy napisac ponizszy skrypt, który przetwarza podany mu na wejscie plik /etc/passwd wypisujac linie zawierajace uzytkownika i odpowiadajacy mu katalog domowy. Laczac go np. z poleceniem grep, mozemy wyswietlic tylko tych uzytkowników, którzy maja
powloke bash, np.
grep /bin/bash /etc/passwd | nazwa_skryptu
Przyklad:
#!/bin/sh IFS=":" read x while [ -n "$x" ]; do set $x echo $1 $6 read x done
Polecenie sluzy do przechwytywania sygnalów wyslanych do procesu skryptu. Liste sygnalów mozemy zobaczyc wpisujac w powloce polecenie trap -lSkladnia polecenia: trap Piszac zamiast polecenia myslnik przypisujemy sygnalowi domyslna akcje.
Przyklad: (nie zapominajmy o odwrotnych cudzyslowach)
#!/bin/sh trap `echo Nie zamkne sie, hehehe` SIGINT trap `echo No dobra bede juz grzeczny; trap - SIGINT` SIGHUP while : do echo Nacisnij ^C aby wyjsc sleep 2 done
Pierwsze polecenie trap powoduje, ze program na wyslanie mu sygnalu SIGINT bedzie reagowal pierwszym komunikatem. Nastepna linijka mówi, ze wysylajac sygnal SIGHUP skrypt równiez wypisze komunikat, ale tez przypisze standardowe dzialanie dla sygnalu SIGINT. Tak wiec poczatkowo naciskajac klawisze ^C nie uda nam sie zamknac programu, ale wystarczy wyslac do procesu sygnal SIGHUP, by bylo to mozliwe. Aby wyslac do dowolnego procesu w systemie jakis sygnal uzywamy polecenia kill [patrz: man kill]. W naszym przypadku bedzie to polecenie kill -SIGHUP PID, gdzie PID to numer identyfikacyjny naszego procesu, sprawdzimy to za pomoca polecenia ps x [patrz: man ps]. PID procesu jest podawany w pierwszej kolumnie, a który to proces znajdziemy po nazwie z ostatniej kolumny.
nazwa_funkcji( ) {
instrukcje
}
lub
function nazwa_funkcji( ) {
instrukcje
}
Parametry do funkcji przekazujemy piszac w miejscu wywolania nazwe funkcji i liste parametrów. Wewnatrz funkcji do parametrów mozemy sie dostac tak, jak w bloku glównym do parametrów przekazanych skryptowi, czyli przez zmienne $1, $2, itd. Odpowiednio sie zmieniaja takze zmienne $#, $*, $@. Po zakonczeniu dzialania funkcji parametrom pozycyjne ($#, $*, $@,$1, ..) przywracane sa ich pierwotne wartosci. Instrukcja ‘return’ powoduje przerwanie wykonania funkcji i przetwarzanie nastepnej linijki od miejsca wywolania. Instrukcje ‘return’ mozna wykorzystac do tego, by funkcja mogla zwrócic jakas wartosc, jednak nie mozna umiescic nazwy funkcji po prawej stronie znaku przypisania, tak wiec nie mozna pobrac tej wartosci. W praktyce zwraca sie jedna z dwu wartosci: jeden lub zero, a wynik dzialania funkcji mozna sprawdzic w instrukcji ‘if’. Aby napisac funkcje, która zwraca jakas wartosc trzeba w tej funkcji uzyc nazwy zmiennej, która bedzie dostepna w miejscu wywolania funkcji. Ponizszy przyklad pokazuje jak napisac funkcje zwracajaca kwadrat liczby przekazanej w parametrze. Wykorzystujemy tu zmienna pomocnicza kw, której zostanie przypisany kwadrat wyrazenia.
Przyklad:
$!/bin/sh kwadrat() { kw=$(($1*$1)) } kwadrat 2 echo $kw
W kolejnym przykladzie wykorzystujemy instrukcje ‘return’ do zwrócenia powodzenia danej funkcji, przy czym wartosc równa zeru bedzie interpretowana jako powodzenie, a rózna od zera jako porazka. Zatem jesli bedziemy chcieli napisac funkcje, która ma zostac uzyta w instrukcji IF lub w
listach AND i OR, to aby wyrazenie przyjelo wartosc prawdy musimy zwrócic zero. Ponizsza funkcja oczekuje dwóch parametrów: pliku i znaku mówiacego o prawie dostepu (jeden ze znaków rwx). Gdy uzytkownik 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
Domyslnie kazda zmienna jest globalna. Umieszczajac w ciele funkcji przed pierwszym uzyciem zmiennej dyrektywe ‘local’ powodujemy, ze jest ona traktowana jako lokalna.
Przyklad:
$ func1 () { local zmienna=1; } $ func2 () { zmienna=2; } $ zmienna=0 $ echo $zmienna 0 $ func1 $ echo $zmienna 0 $ func2 $ echo $zmienna 2
Podajac jako parametr nazwe katalogu mozemy za pomoca ponizszego skryptu zdjac atrybut wykonywalnosci dla wszystkich plików danego katalogu i jego podkatalogów. Warto zauwazyc, ze BASH dopuszcza rekurencje. To samo mozna zrobic krócej wykorzystujac 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
Gdy wywolujemy skrypt w powloce dla skryptu tworzone jest nowe srodowisko, podobnie jesli wywolamy w skrypcie jakis inny skrypt lub program dzieje sie podobnie. Polecenie SOURCE pozwala wykonac skrypt w biezacym kontekscie (bez tworzenia nowego srodowiska). Ma to miedzy innymi takie zastosowanie jak polecenie include z jezyka C wlaczajace do pliku programu inny plik. Tak wiec mozemy oddzielic plik z funkcjami od bloku glównego.
Przyklad:
#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 gló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 pisac SOURCE mozemy uzyc jego krótkiego odpowiednika, czyli pojedynczej kropki, np.:
. funkcja
Polecenie pozwala wywolac program podany w parametrze, o ile jednak zwykle wywolanie programu tworzy nowe srodowisko, to polecenie exec powoduje, ze biezacy kontekst procesu zostaje zamazywany przez kontekst programu wywolywanego. Nie mozna powrócic do skryptu powloki w
przeciwienstwie do polecenia source, któro nie zmienia kontekstu, lecz podaje polecenia z pliku biezacej powloce bez tworzenia nowego srodowiska. O ile w przypadku polecenia source parametrem byl dowolny plik tekstowy zawierajacy polecenia do wykonania, to argumentem polecenia exec moze byc równiez skompilowany program. Mozemy sprawdzic dzialanie uruchamiajac
np. jeden ze skryptów piszac exec nazwa_skryptu. Po takim wywolaniu i zakonczeniu skryptu nie bedzie juz powloki, w której go wykonalsmy, gdyz jej kontekst zostal zastapiony przez kontekst skryptu.
Polecenie to wypisuje na standardowe wyjscie ilosc linii, slów i bajtów pliku podanego w parametrze. Podajac odpowiednie opcje mozemy wybrac interesujace nas informacje, które zostana podane na wyjscie.
Opcje polecenia ‘wc’ |
|
-c, –bytes, –chars |
wydrukowanie ilosci bajtów |
-w, –words |
wydrukowanie ilosci slów |
-l, –lines |
wydrukowanie ilosci linii |
Przyklad:
$ dzis=$(date | awk '{print $3}') $ last | grep root | awk '$5=='$dzis | wc -l
Wywolujac powyzsze polecenia dowiemy ile razy dzisiejszego dnia logowal sie root.
Policzmy ilosc obiektów w katalogu:
$ ls -1 | wc -l
A teraz ilosc linii w pliku:
$ cat nazwa_pliku.txt | wc -l
Polecenie dla kazdej linii z wejscia wycina okreslone fragmenty, przy czym dla kazdej linii jest to taki sam fragment.
Wejsciem moga byc pliki podane w parametrze badz standardowe wejscie.
Opcje polecenia ‘cut’ |
|
-b, –bytes lista_bajtów |
wypisz wylacznie bajty wyliczone w lista_bajtów |
-c, –characters lista_znaków |
wypisz wylacznie znaki wyliczone w lista_znaków (opcja równowazna -b, szczególy w manualu) |
-f, –fields lista_pól |
wypisz wylacznie pola wyliczone w lista_pól |
-d, –delimiter delim |
separator pól (standardowo tabulator) |
-s, –only-delimited |
nie drukuj linii nie zawierajacych separatora pól(ma zastosowanie w przypadku opcji -f) |
lista_bajtów, lista_znaków i lista_pól to ciag liczb badz zakresów oddzielonych przecinkami, najlepiej zrozumiec to na przykladzie,
Przyklad:
$ 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
Domyslnym separatorem pól jest tabulator, wiec jesli na wejscie podamy ciag spacji nie zostanie on uznany za separator. Podobnie jesli obierzemy za separator spacje, tabulator nie bedzie separatorem. Problem moze rozwiazac polecenie ‘col’, któro miedzy innymi zamienia tabulatory na spacje. Taki potok wygladalby nastepujaco:
cat plik | col -x | cut -f 1 -d ' '
Polecenie tlumaczy lub usuwa znaki ze standardowego wejscia, wynik zapisuje na standardowe wyjscie. Musimy do polecenia przekazac jeden lub dwa zbiory znaków. Jesli beda to dwa zbiory bedzie dokonywane tlumaczenie ze zbioru pierwszego na drugi. W przypadku przekazania jednego zbioru dokonuje sie w zaleznosci od przekazanych opcji kasowania lub sciskania znaków. Sciskania
znaków mozna takze dokonywac w przypadku dwóch zbiorów. Nie zostaly tu wymienione wszystkie kombinacje opcji. Nie zostaly tez opisane przypadki, kiedy zbiory pierwszy i drugi nie sa równej dlugosci lub znaki sie powtarzaja. Aby sprawdzic jak polecenie reaguje w takim wypadku
zajrzyj do podrecznika systemowego.
Opcje polecenia ‘tr’ |
|
-s, –squeeze-repeats |
zastepuje sekwencje powtórzonych znaków zbioru pierwszego pojedynczym wystapieniem tego znaku |
d, –delete |
usuwa znaki zawarte w zbiorze pierwszym_ |
-c, — complement |
jesli podany przed zbiorem pierwszym pod uwage jest brane dopelnienie zbioru pierwszego (znaki nie bedace w zbiorze) |
Zbiór znaków moze byc:
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 biala spacja (tabulator, spacja) |
cntrl |
Znaki kontrolne |
digit |
Cyfry |
graph |
Znaki drukowalne (bez spacji) |
lower |
Male litery |
|
Znaki drukowalne (ze spacja) |
punct |
Znaki interpunkcyjne |
space |
Dowolny bialy znak |
upper |
Duze litery |
xdigit |
Cyfry szestnastkowe |
Przyklad:
$ tr a-z A-Z $ tr [:lower:] [:upper:] # obie linijki zamieniaja male znaki na duze. $ tr -cd [:alnum:] # kasuje wszystkie znaki niealfanumeryczne
Przyklad:
$ for plik in *.HTM; do > mv $plik `echo ${zm%.HTM} | tr A-Z a-z`.html > done
Powyzsza petla zamienia wszystkie nazwy plików o rozszerzeniach *.HTM na nazwy o rozszerzeniach *.html zamieniajac przy tym wszystkie litery duze na male.
“grep” jest angielskim akronimem od slów global regular expression print, czyli drukowanie globalnych wyrazen regularnych.
Przyklady zastosowan:
Polecenie “grep” sluzy do wyszukiwania wzorcu z pliku i przekierowywania. Komenda ta wyswietla linie pasujace lub nie do okreslonego wzorca.
Uproszczona skladnia:
grep [-v] wzorzec [Plik]
-v oznacza negacje wzorca (czyli wzorzec nie moze wystapic);
wzorzec – to lancuch znaków do wyszukiwania, moze zawierac wyrazenie regularne;
Plik – plik/lista plików do przeszukania;
Przyklady:
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 poczatku wersu; grep 'Go*gle' plik - znajduje wyraz 'Gogle', 'Google' itd; grep '[0-9]' - znajduje dowolny ciag znaków z zakresu od 0 do 9;
zródlo: http://pl.wikipedia.org/wiki/Grep
Zadania/sytuacje:
grep -l 'main' *.txt
podaje nazwy wszystkich plików txt z biezacego katalogu, których zawartosc zawiera `main’.
grep -r 'hello world' /home/user
szuka ‘hello world’ we wszystkich plikach pod katalogiem /home/user.
grep -e '--hello world--' *
szuka wszystkich linii zawierajacych ‘–hello world–‘. Bez -e , grep wzialby ‘–hello world–‘ jako liste opcji.
grep -w 'hello' *
szuka tylko tych wystapien ciagu hello, które sa calymi wyrazami.
Mozna zastosowac ” aby dopasowac poczatek i koniec ciagu:
grep 'hello>' *
wyszukuje tylko ciagi konczace sie na hello.
grep -C 2 'hello' *
wyswietli 2 linie zawartosci przy kazdej z dopasowanych linii zawierajacej hello.
grep 'username' /etc/passwd /dev/null
ps -ef | grep '[c]ron'
Pominiecie nawiasów kwadratowych, dopasowywuje nie tylko linie wyjsciowa z polecenia ps dotyczaca cron ale i linie wyjsciowa ps dla samego procesu grep.
ps -ef | grep 'cron'
wyswietli:
user 3457 2281 0 13:53 pts/1 00:00:00 grep cron root 5505 1 0 Feb29 ? 00:00:00 /usr/sbin/cron
Mozna to takze ograniczyc poprzez zastosowanie opcji -v, która oznacza negacje wzorca:
ps -ef |grep 'cron' |grep -v grep
grep 'hello world' /home/user/*.txt | grep 'zuza,pralka'
grep wyswietli wszystkie linie zawierajace `hello world’, oraz/i `zuza,pralka’.
cat /etc/passwd | grep 'user' - /etc/group
find /home/user -name '*.txt' -print | xargs grep 'hello world' /dev/null
polecenie przeszuka tylko pliki txt pod wzgledem wystepowania w nich, ciagu ‘hello world’
sed (ang. Stream EDitor – edytor strumieniowy) – program sluzacy do przetwarzania plików tekstowych.
sed jest filtrem – pobiera dane w postaci wierszy tekstu ze standardowego wejscia, przetwarza je zgodnie z poleceniami podanymi w wierszu polecen lub zapisanymi w pliku i przesyla wyniki operacji na standardowe wyjscie. Cecha charakterystyczna seda jest to, ze wykonuje on na danym wierszu wszystkie polecenia, jakie sa do wykonania. Poniewaz przetwarzanie odbywa sie wiersz po wierszu, sed nie ma praktycznie zadnych ograniczen na wielkosc przetwarzanego pliku.
Sed nadaje sie szczególnie do przetwarzania plików o pewnej strukturze. Napisany zostal pierwotnie przez Lee E. McMahona dla systemu UNIX w roku 1973, w chwili obecnej dostepny jest praktycznie dla kazdego systemu operacyjnego, który dysponuje wierszem polecen.
Zestaw polecen programu sed wzorowany jest na poleceniach programu ed i wiekszosc z nich dziala podobnie, jesli uwzgledni sie specyfike seda. Na przyklad, polecenie 25d dziala w sedzie nastepujaco: sprawdza, czy biezacy wiersz jest 25 wierszem przetwarzanego pliku i jesli tak, to nie kieruje go na wyjscie (“usuwa” go), a jesli nie, wiersz pojawi sie na wyjsciu. Jednak nie wszystkie polecenia eda mogly zostac zaimplementowane, w szczególnosci te, które odpowiedzialne sa za kopiowanie lub przenoszenie tekstu. Zamiast tego, sed dysponuje buforem, który pozwala przechowac wybrane wiersze i zestawem polecen do manipulacji nimi. Na przyklad, polecenie eda 25t76 (skopiuj wiersz 25 do 76) mozna zrealizowac w sedzie jako dwa polecenia: 25h; 76g – przechowaj wiersz 25 w buforze i wstaw po napotkaniu wiersza 76.
sed -e ‘s/dobry/zly/g’ plik_wejsciowy > plik_wyjsciowy
s oznacza zastepowanie, g globalne, w calym wierszu. Po pierwszym ukosniku pojawia sie wyrazenie regularne, opisujace tekst, który ma byc wyszukany, po drugim wyrazenie, które ma zastapic wyszukany tekst. Polecenie zastepowania jest najczesciej wykonywanym poleceniem sed’a.
sed -f polecenia.sed plik_wejsciowy > plik_wyjsciowy
Nastepujace wywolanie usuwa z pliku wszystkie puste wiersze, lub te, które zawieraja wylacznie spacje:
sed -e '/^ *$/d' input_File_Name
Przyklad ten wykorzystuje kilka meta znaków uzywanych w wyrazeniach regularnych sed’a:
De facto sed jest prostym jezykiem programowania i mimo ze nie pozwala na korzystanie z zadnych zmiennych, dopuszcza jedynie proste instrukcje skoku, to jest jezykiem zupelnym w sensie Turinga.
sed wyewoluowal z grepa, programu wyszukujacego frazy tekstowe w plikach i byl jednym z pierwszych programów unixowych pozwalajacych na edycje plików z wiersza polecen, a jego pojawienie sie stanowilo impuls do powszechnego uzywania wyrazen regularnych. Podobny w idei dzialania awk moze byc traktowany jako nastepca seda. Wraz z awkiem, sed uwazany jest za prekursora jezyka Perl. W szczególnosci, s/// jest poleceniem Perla.
Mimo sedziwego wieku sed nadal jest uzywany i rozwijany ze wzgledu na szybkosc dzialania. W specyficznych operacjach bije na glowe zarówno AWKa jak i Perla. Ciekawym rozwinieciem seda jest GNU sed pozwalajacy na bezposrednia zmiane przetwarzanego pliku i Super-sed, którego skladnia jest zgodna ze skladnia Perla.
zródlo: http://pl.wikipedia.org/wiki/Sed_(program)
przyklady uzycia: http://www.gentoo.org/doc/pl/articles/l-sed1.xml
skrypty sed: http://sed.sourceforge.net/
“jednolinijkowce”: http://sed.sourceforge.net/sed1line.txt
AWK jest interpretowanym jezykiem programowania, którego glówna funkcja jest wyszukiwanie i przetwarzanie wzorców. Jest takze nazwa programu poczatkowo dostepnego dla systemów operacyjnych bedacych pochodnymi UNIX-a, obecnie takze na inne platformy. Nazwa jezyka pochodzi od pierwszych liter nazwisk jego autorów Alfreda V. Aho, Petera Weinbergera i Briana Kernighana i czasami jest zapisywana malymi literami oraz odczytywana jako jedno slowo awk.
Definicja jezyka 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 wlasciwosciami, zdefiniowanymi w wersji awk z SysVR4.
W wierszu polecen podaje sie opcje dla awk, tekst programu (jesli nie podano go poprzez opcje -f lub –file) i wartosci, które maja byc udostepnione w predefiniowanych zmiennych ARGC i ARGV.
Zródlo: http://pl.wikipedia.org/wiki/AWK
awk -f …
awk '{ print $1 }' ...
powoduje to wypisanie pierwszego pola z kazdego rekordu: np. pierwszego wyrazu.
Tutorial awk: http://sokrates.mimuw.edu.pl/~sebek/awk.html
Find – program sluzacy do przeszukiwania systemu.
Skladnia:
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 przyklad wszystkie pliki *.txt
–name pattern – nazwa pliku okrelona przy pomocy danego wzorca;
–atime $n$ – do pliku zagladano $n$ dni wczesniej;
–ctime $n$ – status pliku zmieniono $n$ dni wczesniej;
–mtime $n$ – zawartosc pliku zmieniono $n$ dni wczesniej;
–user username – plik nalezy do danego uzytkownika;
–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 – lacze nazwane (FIFO) f – zwykly plik l – dowiazanie symboliczne s – gniazdo
W okresleniu cechy mozna stosowac oznaczenia “+n” lub “-n”: pierwsze znaczy “wiecej, niz… ”, drugie “mniej, niz… ” np. -atime +15 oznacza pliki otwierane przed wiecej, niz 15-oma dniami.
–print – po prostu drukuje nazwe pliku;
–exec polecenie – wykonanie dla kazdego ze znalezionych plików danego polecenia;
–ok polecenie – jak wyzej ale trzeba potwierdzic przed kazdym wykonaniem.
zamiast:
find / -name core -exec rm -f {} \;
wersja z xargs
find / -name core -print | xargs rm -f
Przyklady zastosowan:
find /home/user/muza -iname shazza
find /home/user/muza ! -name 'shazza'
find `pwd` -exec ls -l '{}' ; | grep "Dec 21"
szukanie podkatalogów w katalogu /katalog nalezacych do uzytkownika osoba
find /katalog/ -user osoba -type d
wyszukaj i skasuj wszystkie pliki z katalogu /tmp nalezace do usera nazwa_usera
find /tmp -user nazwa_usera -exec rm -rf {} \;
Szukanie w biezacym katalogu plików o rozmiarach przekraczajacych 10 MB z wyswietleniem szczegulów (ls -l):
find . -size +10485760c -exec ls -l {} \;
szukanie ciagu, gdy nie wiadomo w jakim pliku jest ciag i w jakim katalogu znajduje sie plik:
find /home/user/ -name "*.txt" -print | xargs grep "szukany_ciag"
szukanie plików, w róznych katalogach – najpierwsz pszeszuka usr, home i na koncu tmp:
find /usr /home /tmp -name "*.jar
pominiecie komunikatów o bledach jesli nie mamy prawa dostepu do któregos z katalogów:
find /usr /home /tmp -name "*.jar" 2>/dev/null
Mozemy takze szukac plików które byly modifikowane albo otwierane pod wzgledem opcji -newer, -anewer, and –cnewer. Jest to podobne do -mtime, -atime, and –ctime.
• –newer wskazuje na pliki, których zawartosc nie byla modyfikowana ostatnio
• –anewer wskazuje na pliki, które byly odczytywane ostatnio
• –cnewer wskazuje na pliki, których status zmienil sie ostatnio
– Aby odnalezc pliki w katalogu domowym /home które byly jakkolwiek edytowane od ostatniego pliku tar:
find ~ -newer backup.tar.gz
szukanie plików po prawach dostepu 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 wyszukac wszystkie pliki w systemie które moga byc edytowane przez wszystkich uzytkowników:
find / -wholename '/proc' -prune -o -type f -perm -0002 -exec ls -l {} \;
#Szukanie plików po uzytkowniku, 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 maja 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 world…
Przyklady:
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
find /home/user -type f -exec chmod a+wr {} \; find /home/user -type d -exec chmod 777 {} \;
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 {} \;
find /directory/log -mtime +30 -print -exec rm -f {} \; >> del_files.log 2> /dev/null #znajdz dzisiejsze logi i skopiuje je do zadanego katalogu find logs/ -type f -mtime -1 -exec cp -v {} /home/user/backup_logs ;
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 nastepnie wylistuje wszystkie pliki z uprawnieniami SUID do pliku suid.txt oraz wszystkie pliki duze pliki (wieksze niz 100 MB) z listingiem do pliku big.txt (przyklad zaciagniety z manuala programu find):
find /var ( -perm +4000 -fprintf /root/suid.txt '%#m %u %pn' ) , ( -size +100M -fprintf /root/big.txt '%-10s %pn' )
Magia find + xargs
druga linia wykonuje sie szybciej niz pierwsza dla duzej ilosci plików
find / -name core -exec rm -f {} \; rm -f $(find / -name core -print)
Innymi slowy wywolujac jednokrotnie polecenie “rm” wlaczajac wszystkie nazwy plików, jest szybsze niz wielokrotne wywolywanie polecenia “rm” osobno dla kazdego pliku.
Jednakze drugie polecenie moze sie nie powiesc, kiedy liczba plików jest bardzo duza i przekracza maksymalna liczbe znaków dozwolonych w jednym poleceniu (komendzie)
“xargs” polaczy wyjscie komendy z pierwszej linii polecenia find i wykona sie wielokrotnie z wielokrotnymi argumentami jezeli bedzie to konieczne aby zapobiec przekroczeniu maksymalnej ilosci dostepnych znaków w jednej komendzie.
find / -name core -print | xargs rm -f
wykonujac proste polecenia mozna latwo zobaczyc sile programu xargs:
find $HOME -maxdepth 2 -name *.jpg -exec echo {} \; find $HOME -maxdepth 2 -name *.jpg | xargs echo
Potega opcji zero!
Druga komenda sie nie powiedzie jezeli którekolwiek z plików bedzie zawieralo spacje 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 rozwiazuje problem:
find $HOME -maxdepth 2 -name *.jpg -print0 | xargs -0 ls