Co to jest BASH Kurs BASH
Kurs BASH
Tradycyjnie pierwszym krokiem do pisania wlasnego kodu jest wyswietlenie na standardowym wyjsciu (stdout), tutaj ekran monitora, oslawionego tekstu "Hello World".
echo "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
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.
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:
#!/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
#!/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 |
echo -n "przykladowy tekst"
Przyklad:
#!/bin/sh echo -e \\a
sleep 1 #wstrzymanie skryptu na 1 sekunde
echo "peep"
echo -e "\a"
'Here documents' - dokumenty miejscowe. Jest to rodzaj przekierowania, które pozwala czesc tresci skryptu traktowac jako standardowe wejscie.
Skladnia:
<
here-document
ogranicznik
#!/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.
! 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
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)
#!/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.
polecenie1 | polecenie2 | polecenie3 | polecenien...
$ /sbin/ifconfig | grep HWaddr > wynik.txt
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).
$ 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.
$ 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].$ 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.
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.
$ touch plik
$ set -o noclobber
$ ls > plik
bash: plik: cannot overwrite existing file
$ ls >| plik
$ set +C
$ echo koniec > plik
Zmienne
$ ile=5
$ echo ile
ile
$ echo $ile
5
$ ile=5+5 # 5+5 jest ciagiem znaków
$ echo ile
5+5
$
Zmienne srodowiskowe
| $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
#!/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
export zmienna
lub
export zmienna=wartosc
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
$
Cudzyslowy i apostrofy
Cudzyslowy
./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
Pozostale sekwencje poprzedzone backslashem (wymienione przy poleceniu echo) nie sa zamieniane.

Apostrofy
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

Tych operatorów mozemy uzywac w nastepujacych konstrukcjach:
$((wyrazenie))
((wyrazenie))
let wyrazenie
Przyklad:
zmienna=0
$ echo $((zmienna=zmienna+2))
2
$ ((zmienna=$zmienna**3));echo $zmienna
8
Do spisu tresci
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 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ą |
|
${parametr:?slowo} |
wartością wyrażenia jest wartość parametru, jeśli |
|
${parametr:+slowo} |
jeśli parametr jest niezdefiniowany bądź null nic |
|
${#parametr} |
zwraca długość zmiennej parametr w znakach |
|
${parametr#slowo} |
zwraca wartość parametru po usunięciu z niego |
|
${parametr##slowo} |
zwraca wartość parametru po usunięciu z niego |
|
${parametr%slowo} |
zwraca wartość parametru po usunięciu z niego |
|
${parametr%%slowo} |
zwraca wartość parametru po usunięciu z niego |
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 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 ||
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
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" ].
Lista AND
Składniainstrukcja1 && 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.
- 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).
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
- 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
- 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
- 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
- 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.
- 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
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.
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 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
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.
- 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
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
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.
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.
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 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) |
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 |
|
|
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.
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'
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
sed (ang. Stream EDitor – edytor strumieniowy) – program służący do przetwarzania plików tekstowych.
- Oto typowy przykład wywołania seda:
sed -e 's/dobry/zły/g' plik_wejściowy > plik_wyjściowy
- 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
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:
- 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
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:
-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
- 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:
find / -name core -exec rm -f {} \;
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
find / -nouser -o -nogroup
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
- 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 {} ).





