Programowanie w
bash-u
dr inż. Ireneusz Mrozek
dr inż. Andrzej Chmielewski
Wydział Informatyki
Politechniki Białostockiej
Powłoka systemowa
bash
Powłoka (shell) – tekstowy interfejs użytkownika w systemach
UNIX/Linux
Powłoka nieustannie realizuje cztery zadania:
wyświetla
prompt
wykonuje
polecenie
przetwarza
polecenie
wczytuje
polecenie
powłoka
Skrypty powłoki
bash
Automatyzacja zadań
Często podczas prac administracyjnych w systemie zachodzi potrzeba
wielokrotnego wykonania tych samych bądź podobnych poleceń.
Celem ułatwienia i ewentualnego zautomatyzowania tych czynności
realizowane polecenia można zapisać w pliku tekstowym.
Pliki tekstowe napisane z pewnymi regułami składni zdefiniowanymi w
danej powłoce nazywane są skryptami.
Skrypty powłoki
bash
Automatyzacja zadań
Skrypty powłoki są plikami tekstowymi ze zgrupowanymi poleceniami
systemu UNIX oraz odpowiednimi strukturami sterującymi.
Podobnie jak programy pisane w wysokich językach programowania,
skrypty pisane i edytowane są w edytorach tekstowych.
Skrypty powłoki nie podlegają procesowi kompilacji i nie są zamieniane na
język maszynowy.
Za wykonanie skryptu odpowiedzialna jest powłoka, która realizuje tutaj
zadanie interpretera.
Rodzaje powłok
bash
System Linux obsługuje wiele typów powłok, w zależności od
upodobań użytkowników.
Bourne Shell (sh), pierwsza powłoka stworzona dla systemu UNIX.
Bourne Again Shell (bash), powłoka napisana przez programistów Free Software
Fundation, shell o charakterze opensource dla systemu GNU.
Korn Shell (ksh), powłoka napisana przez David’a Korn’a. Rozwinięcie powłoki
Bourne
C Shell (csh), powłoka napisana przez Bill’a Joy’a, autora edytora vi. Zawiera wiele
struktur zapożyczonych z języka C.
Terminal Based C Shell (tcsh), rozszerzona wersja powłoki Berkeley UNIX C shell
csh.
Debian Almquist shell (dash), uproszczona wersja bash-a; powłoka domyślna
m.in. w dystrybucjach Ubuntu
Powłoka bash
bash
Najpopularniejszą powłoką jest bash. Jest powłoką domyślną w
przeważającej większości dystrybucji.
W skrypcie można zadeklarować, która powłoka ma go interpretować,
deklarując to w pierwszej linii.
#!/bin/sh
dla Bourne shella (w najnowszych dystrybucjach podlinkowana jest pod ten
skrypt powłoka domyślna
lrwxrwxrwx 1 root root 4 lut 19 2014 /bin/sh > bash
W przypadku wymuszenia powłoki Bourne-Again-Shella
#!/bin/bash
Pierwszy skrypt
bash
Najpopularniejszą powłoką jest bash. Jest powłoką domyślną w
przeważającej większości dystrybucji.
Skrypt:
#!/bin/bash
directory=`pwd`
echo The date today is `date`
echo The current directory is $directory
chmod 700 myfirstscript.sh
./myfirstscript.sh
The date today is czw, 26 lut 2015, 22:41:52 CET
The current directory is /home/student/tmp
Programowanie powłoki
bash
Trzy najważniejsze elementy w programowaniu powłoki
Zmienne powłoki, skrypty często potrzebują przechowywać w pamięci
wartości, które zostaną użyte później. Zmienne powłoki są symbolicznymi
nazwami pozwalającymi na dostęp do przechowywanych wartości.
Operatory, powłoka udostępnia wiele różnych operatorów w tym operatory
arytmetyczne
Struktury sterujące, oprócz sekwencyjnej realizacji poleceń zapisanych w
skrypcie (sequential logic) możliwe są również rozgałęzienia (decision
logic), pętle (looping logic) czy wybieranie działania z wielu możliwych
alternatyw (case logic).
Parametry skryptu
bash
./skrypt.sh p1 p2 p3
$0 – ./skrypt.sh (nazwa skryptu), samą nazwę można uzyskać za pomocą
'basename $0'
$1 – p1
$2 – p2
$3 – p3
$# - 3 (liczba argumentów)
$* - wszystkie argumenty jako jeden ciąg znaków
$$ - pid aktualnego procesu (skryptu)
$? – rezultat ostatnio zakończonego polecenia
Polecenie
shift
przesuwa wszystkie argumenty o jeden w lewo
Jeśli $1=”To”, $2=”jest”, $3=”pierwszy”, $4=”skrypt”, to po wykonaniu
polecenia
shift
, mamy: $1=”jest”, $2=”pierwszy”, $3=”skrypt”.
Można również użyć z parametrem określającym wielkość przesunięcia:
shift 2
Znaki specjalne
bash
Znaki specjalne
\z – zamaskowanie specjalnego znaczenia, np. \$
# - rozpoczęcie komentarza (do końca linii)
; - sekwencyjne wykonanie poleceń
& - uruchomienie polecenia w tle
| - łącze komunikacyjne
$ - odwołanie do zmiennej środowiskowej
*,? - substytucja nazw plików
||, && sekwencje warunkowe
< > - przekierowania
Zmienne
bash
Trzy podstawowe kategorie zmiennych: zmienne
konfiguracyjne, zmienne środowiskowe, zmienne powłoki
Zmienne są symbolicznymi nazwami reprezentującymi wartości
przechowywane w pamięci.
Zmienne konfiguracyjne są zmiennymi służącymi do konfiguracji
systemu. Zwykły użytkownik nie powinien ich zmieniać.
Zmienne środowiskowe są zmiennymi służącymi do przechowywania
informacji o bieżącej sesji użytkownika.
Zmienne powłoki to zmiennie, które tworzone są z linii poleceń lub
podczas realizacji skryptu.
Zmienne
bash
Trzy podstawowe kategorie zmiennych: zmienne
konfiguracyjne, zmienne środowiskowe, zmienne powłoki
Zmienne konfiguracyjne i zmienne środowiskowe posiadają
standardowe nazwy takie jak HOME, PATH, SHELL, USERNAME, czy
PWD.
Zmienne konfiguracyjne i zmienne środowiskowe zapisujemy zwykle
dużymi literami w odróżnieniu od zmiennych zdefiniowanych przez
użytkownika zapisywanych małymi literami.
Do wartości zmiennych odwołujemy się poprzez poprzedzenie nazwy
zmiennej znakiem „$”
$ echo $PATH
lub
$ echo ${PATH}
$ echo $myval
lub
$ echo ${myval}
Zmienne środowiskowe i konfiguracyjne
bash
Wyświetlanie zmiennych: set oraz printenv
$ set
BASH=/bin/bash
BASH_VERSINFO=([0]="4" [1]="3" [2]="11" [3]="1" [4]="release"
[5]="x86_64pclinuxgnu")
BASH_VERSION='4.3.11(1)release'
COLORTERM=gnometerminal
DEFAULTS_PATH=/usr/share/gconf/gnomefallbackcompiz.default.path
DESKTOP_SESSION=gnomefallbackcompiz
DISPLAY=:0.0
GDMSESSION=gnomefallbackcompiz
GDM_LANG=pl_PL
$ printenv
XDG_VTNR=7
XDG_SESSION_ID=c3
CLUTTER_IM_MODULE=xim
SELINUX_INIT=YES
SESSION=gnomefallbackcompiz
GPG_AGENT_INFO=/run/user/1000/keyring7r5fQ0/gpg:0:1
TERM=xterm
SHELL=/bin/bash
Zmienne środowiskowe i konfiguracyjne
bash
Przykłady najpopularniejszych zmiennych
Zmienna
Opis
PATH
Lista katalogów oddzielonych dwukropkami, w których
wyszukiwane będą polecenia (aplikacje)
EDITOR
Domyślny edytor tekstu
SHELL
Domyślna powłoka
USER
LOGNAME
USERNAME
Nazwa użytkownika
UID
Identyfikator użytkownika
HOME
Katalog domowy użytkownika
LANG
LC_ALL
Ustawienia języka (locale)
TZ
Strefa czasowa
IFS
Domyślny separator
Zmienne środowiskowe i konfiguracyjne
bash
Przykłady najpopularniejszych zmiennych
Zmienna
Opis
PS1
Znak zachęty (prompt); można zdefiniować również PS2,
PS3 oraz PS4
PWD
Bieżący katalog
RANDOM
Wartość losowa (inna przy każdym odwołaniu)
Zmienne
bash
Wartości zmiennych powłoki generalnie ustawiane są w
identyczny sposób (oprócz C-shell)
zmienna=wartosc
$ x=41; echo $x
41
$ unset x; echo $x
W powłoce C-shell do ustalenia wartości zmiennej używane jest polecenie
set.
Zmienne mogą przyjmować konkretne poleceń. Mogą też przyjmować
wynik zadanego polecenia.
$ mydir=`pwd`; echo $mydir
/home/student
Tablice
bash
Definiowanie tablic
tablica=(element1 element2 element3)
echo ${tablica[0]}
echo ${tablica[1]}
echo ${tablica[2]}
Znak „#” pozwala uzyskać długość danego elementu tablicy:
echo ${#tablica[0]}
oraz liczbę elementów tablicy:
echo ${#tablica[@]}
Tablice
bash
Odwołanie do elementów tablicy oraz dodawanie nowych
Odwołanie do elementów tablicy
${nazwa_zmiennej[wska?nik]}
Wskaźnikami są indeksy elementów tablicy, począwszy od 0 do n oraz @, *.
${nazwa_zmiennej}
odwołanie do elementu 0
${nazwa_zmiennej[@]} lub ${nazwa_zmiennej[*]} wszystkie
elementy tablicy
Gdy tablica nie zawiera żadnych elementów to odwołanie:
${nazwa_zmiennej[wska?nik]}
zwraca ciąg pusty.
Dodawanie elementów do tablicy
nazwa_zmiennej[wska?nik]=warto??
tablica=(element1 element2 element3)
tablica[3]=element4
echo ${tablica[@]}
Operatory
bash
Operatory powłoki można podzielić na cztery kategorie
1. Operatory przypisania
2. Operatory rozwinięcia
3. Operatory arytmetyczne
4. Przekierowania i łącza komunikacyjne
Operator przypisania
bash
Operatory używane do przypisania wartości zmiennej.
Najczęściej używanym operatorem przypisania jest „=”.
Przypisując ciągi znakowe zawierające znaki białe należy je ująć w cudzysłów
(pojedynczy lub zwykły).
uczelnia=”Politechnika Białostocka”
Odwróconych apostrofów używamy, gdy chcemy do zmiennej przypisać wynik
polecenia.
katalog=`pwd`
Operator rozwinięcia
bash
Operatory rozwinięcia używane są do określenia wartości
zmiennej środowiskowej.
Podstawowym operatorem rozwinięcia jest znak „$”, który poprzedza nazwę
zmiennej, której wartość chcemy odczytać.
Przy odwoływaniu się do wartości zmiennej można jej nazwę ująć w cudzysłów (ale
nie w apostrofy).
Różnica pomiędzy znakami cudzysłowu przy rozwijaniu zmiennych
$ echo "$HOME"
/home/student
$ echo '$HOME'
$HOME
Operatory arytmetyczne
bash
Operatory arytmetyczne wykorzystywane do obliczeń
Operator
Opis
-, +
Operator unarny do określania znaku
!, ~
Negacja logiczna (!X zwraca 0, gdy X jest niezerowe ) oraz
negacja bitowa (~X)
*, /, %
Operator mnożenia, dzielenia i reszty z dzielenia
+, -
Dodawanie i odejmowanie
>, <
Operator większości (gt) oraz mniejszości (lt)
>=, <=
Operator mniejszy równy (ge) oraz mniejszy równy (le)
=, !=
Operator równości oraz różności
Przykłady operacji arytmetycznych
bash
Łącznie z operatorami arytmetycznymi mają zastosowania
wszystkie podstawowe reguły matematyczne
Łącznie z operatorami arytmetycznymi mają zastosowania wszystkie podstawowe
reguły matematyczne
$ let a=5+10*2
$ echo $a
25
Domyślnie wartości przechowywane są jako ciągi znakowe
$ number=7+5
$ echo $number
7+5
$ x=2; y=3
$ z1=x+y; z2=$x+$y
$ echo $z1 $z2
x+y 2+3
Przykłady operacji arytmetycznych
bash
Aby wyznaczyć wartość zadanego działania należy użyć
polecenia expr, nawiasów ()
$ x=1
$ expr $x + 100
# spacja przed/po operatorze '+'
101
Przypisanie wartości wyrażenia do zmiennej
$ x=`expr $x + 1`
# potrzebna spacja przed/po operatorze '+'
$ x=$(expr $x + 1)
# spacja przed/po operatorze '+'
x=$(($x+1))
# bez spacji przed/po operatorze '+'
Operatory przekierowania
bash
Operaory: >, >>, <, |
> plik
- przekierowanie standardowego wyjścia do pliku. Jeżeli plik nie istnieje to
zostanie założony, jeżeli istnieje to jego zawartość zostanie skasowana
$ echo 'tekst' > file.txt
>> plik
- przekierowanie standardowego wyjścia do pliku. Jeżeli plik nie istnieje
to zostanie założony, jeżeli istnieje to wynik polecenia zostanie dodany do
zawartości pliku
$ echo 'tekst' >> file.txt
< plik
- przekierowanie standardowego wejścia z pliku.
$ echo "5 7 8" > tmp
$ read a b c < tmp
$ echo $a $b $c
5 7 8
Łącze komunikacyjne - Potoki
bash
Kilka komend możemy połączyć potokiem, rozdzielając je
metaznakiem „|”
$ ls al | grep i txt | more
Powyższe polecenie zbudowane jest z poleceń
$ ls al > tmp
$ grep txt tmp > tmp
$ more tmp
Dodatkowo należałoby skasować pliki pośrednie
$ rm tmp
Strumienie
bash
stdin, stdout, stderr
stdin
– standardowe wejście (deskryptor 0) — zwykle klawiatura komputera
stdout – standardowe wyjście (deskryptor 1) — zwykle terminal
stderr
– standardowe wyjście błędów (deskryptor 2) — zwykle terminal
Przykład: wylistowanie dwóch plików z których tylko jeden istnieje
$ ls al a.txt b.txt
ls: nie ma dost?pu do b.txt: Nie ma takiego pliku ani katalogu
rwrwr 1 student student 76 mar 6 23:37 a.txt
Przekierowanie stdout do pliku
$ ls al a.txt b.txt > plik.ok
ls: nie ma dost?pu do b.txt: Nie ma takiego pliku ani katalogu
$ cat plik.ok
rwrwr 1 student student 76 mar 6 23:37 a.txt
Przekierowanie stderr do pliku
$ ls al a.txt b.txt 2> plik.err
rwrwr 1 student student 76 mar 6 23:37 a.txt
$ cat plik.err
ls: nie ma dost?pu do b.txt: Nie ma takiego pliku ani katalogu
Strumienie
bash
stdin, stdout, stderr
Przekierowanie danych ze strumieni do różnych plików
$ ls al a.txt b.txt 2> plik.err 1> plik.ok
$ cat plik.err
ls: nie ma dost?pu do b.txt: Nie ma takiego pliku ani katalogu
$ cat plik.ok
rwrwr 1 student student 76 mar 6 23:37 a.txt
Przekierowanie danych ze strumieni stdout i stderr do tego samego pliku
$ ls al a.txt b.txt &> plik.err
$ cat plik.err
ls: nie ma dost?pu do b.txt: Nie ma takiego pliku ani katalogu
rwrwr 1 student student 76 mar 6 23:37 a.txt
Jeśli nie jesteśmy zainteresowani danymi z jakiegoś strumienia, możemy go
przekierować do urządzenia nieistniejącego
/dev/null
$ ls al a.txt b.txt 2> /dev/null
rwrwr 1 student student 76 mar 6 23:37 a.txt
Strumienie
bash
stdin, stdout, stderr
Przekierowanie danych ze strumienia stdout do stderr.
$ ls al a.txt b.txt 1>&2
ls: nie ma dost?pu do b.txt: Nie ma takiego pliku ani katalogu
rwrwr 1 student student 76 mar 6 23:37 a.txt
Domyślnie stdin i stderr wskazują na terminal, stąd w poprzednim przykładzie nie
widać, czy strumień stdin został przekierowany. Przekierujmy więc stderr do pliku.
$ ls al a.txt b.txt 2> plik.err 1>&2
$ cat plik.err
ls: nie ma dost?pu do b.txt: Nie ma takiego pliku ani katalogu
rwrwr 1 student student 76 mar 6 23:37 a.txt
A jak zinterpretować poniższe polecenie?
$ program <dane.txt >wyniki.txt 2>bledy.txt &
Strumienie
bash
Przykłady
Kasowanie plików
core
bez żadnych komunikatów (często używane polecenie w
cron-ie)
$ rm f $(find / name core) &> /dev/null
Eksport zmiennych
bash
Zmienne, które nie są wyeksportowane nie będą widziane ani w
skryptach ani w uruchomionych programach (procesach
potomnych).
$ cat myscript
echo '====='
echo $A
echo '====='
$ A=hello
$ echo $A
hello
$ ./myscript
=====
=====
$ export A
$ ./myscript
=====
hello
=====
Przesłanianie zmiennych
$ echo $A
hello
$ A=witaj ./myscript
=====
witaj
=====
Struktury sterujące
bash
if, while, for, until, case
if … then … else … fi
if … then …elif … else … fi
for … in … do … done
while … do … done
until … do … done
case … in … esac
Struktury sterujące
bash
Przykład: if
echo –n "Enter your password: "
read input
if
[ $input = "secret" ]
then
echo "welcomed “
echo “to the secret world!”
else
echo "go away!"
fi
Poniższe instrukcje są równoważne:
if
test $input = “secret”
if
[ $input = "secret" ]
Struktury sterujące
bash
Skrócony zapis instrukcji warunkowej
|| - gdy instrukcja ma się wykonać przy niespełnionym warunku
if test $x –ne $y
then
echo „warto?? x jest ró?na od warto?ci y”
fi
Powyższą instrukcję można zapisać jako:
test $x –eq $y || echo „warto?? x jest ró?na od warto?ci y”
Struktury sterujące
bash
Skrócony zapis instrukcji warunkowej
&& - gdy instrukcja ma się wykonać przy spełnionym warunku
if test $x –eq $y
then
echo „warto?? x jest równa warto?ci y”
fi
Powyższą instrukcję można zapisać jako:
test $x –eq $y && echo „warto?? x jest równa warto?ci y”
Struktury sterujące
bash
Przykład: while
while
[ "$input" != "secret" ]
do
echo "Enter your password"
read input
done
echo "welcome!"
count=1;
limit=10;
while [ $count lt $limit ]
do
sleep 5; echo “Get up and do some exercise”
count=`expr $count + 1`
done
Struktury sterujące
bash
Przykład: while w pętli nieskończonej
while
[ 1 ]
do
echo n "Enter your password"
read input
if
[ $input = "secret" ]
then
break
else
echo n "Try again... "
fi
done
Struktury sterujące
bash
Przykład: until
secret='haslo'
until
[ "$input“ != "secret" ]
do
echo n"Enter your password: "
read input
done
echo "welcome!"
Struktury sterujące
bash
Przykład: case
echo "Podaj cyfre z przedzialu 03"
read d
case "$d" in
"0") echo "zero" ;;
"1") echo "jeden" ;;
"2") echo "dwa" ;;
"3") echo "trzy" ;;
*) echo "Wprowadzono bledne dane"
esac
Rodzaje warunków
bash
Porównania ciągów znakowych oraz arytmetyczne
Porównanie ciągów znakowych
string1 == string2
– czy dwa ciągi znakowe są sobie równe
n string1
– string1 jest różny od null
z string1
– string1 jest null
Alternatywnie można wykorzystać warunek:
if [ ”x$string” = ”x” ]
Porównania arytmetyczne
exp1 –eq exp2
– dwie wartości są sobie równe
exp1 –ne exp2
– dwie wartości są różne
gt, ge, lt, le – >, >=, <, <=
!exp1
– prawda jeżeli exp1 jest false
Wzorce
bash
Użycie podwójnych nawiasów określających warunek pozwala
wykorzystać wzorce.
Do sprawdzenia czy pierwszy parametr przekazany do skryptu
rozpoczyna się od znaku „-” za którym jest liczba można użyć
następującej konstrukcji:
if [[ "$1" == [09]+ ]]
then
….
Do sprawdzenia czy zmienna input ma postać abc po czym może
wystąpić cyfra, można użyć następującej konstrukcji:
if [[ "$input" = abc[09]* ]]
then
….
Warunki dotyczące plików
bash
Wybrane klucze dotyczące plików
-d file: prawda jeżeli file jest katalogiem
-e file: prawda jeżeli istnieje plik file
-f file: prawda jeżeli file jest regularnym plikiem
-r file: prawda jeżeli posiadamy prawo czytania pliku (-w, -x)
-s file: prawda jeżeli rozmiar pliku jest większy niż 0
if [ f file.txt ];
then
echo 'Plik file.txt istnieje'
fi
Funkcje
bash
Słowo kluczowe: function
#!/bin/bash
function fun1 {
echo ”hi”
}
function fun2 {
echo $1
}
fun1
fun2 Hello
fun2 World
script.sh
$ ./script.sh
hi
Hello
World
Wykonywanie poleceń w tle
bash
Wykonywanie poleceń w tle
$ ls al &
[1] 27121
$ razem 10652
drwxrwxrx 3 student student 4096 mar 8 14:14 .
drwxrwxrx 6 student student 4096 lut 20 17:20 ..
rwrwr 1 student student 816503 mar 4 21:32 abc.txt
rwrwr 1 student student 340576 mar 4 21:32 cba.txt
znak zachęty wypisany przed wykonaniem polecenia
PID procesu wykonywanego w tle
Grupowanie poleceń wykonywanych w tle
$ (echo „Pliki z bie??cego katalogu”; ls al) &
Substytucje
bash
Substytucje
Substytucje zmiennych środowiskowych
Substytucje nazw plików
Substytucje poleceń
Aliasy
Substytucje zawsze wykonywane są przed wykonaniem
polecenia
Substytucje poleceń
bash
Substytucje zawsze wykonywane są przed wykonaniem polecenia
Substytucja poleceń polega na wykonaniu polecenia ujętego w
odwrócone apostrofy przed realizacją polecenia głównego.
$ A=`pwd`
$ echo '$A'
$A
$ echo $A
/home/student
$ echo ”$A”
/home/student
Substytucja nazw plików
bash
Substytucja nazw plików polega na rozwijaniu określonych
metaznaków w nazwy plików.
*
- Pasuje do każdej nazwy, także do pustej
?
- Pasuje do każdego znaku
[…]
- Pasuje do każdego znaku zawartego między nawiasami
[xy]
- Pasuje do każdego znaku z zakresu x-y
[!...]
- Pasuje do wszystkich znaków z wyjątkiem występujących po "!"
Wszystkie pliki z rozszerzeniem .txt
$ ls al *.txt
Pliki rozpoczynające się małą literą 'a' oraz kończące się małą literą 'z'
$ ls al a*z
Pliki rozpoczynające się od litery
$ ls al [azAZ]*
Aliasy
bash
Aliasy umożliwiają skrócenie długich poleceń lub połączenie serii poleceń
w jedno.
Definiowanie aliasu:
$ alias la="ls la"
$ alias clean="rm *~ .*~ core *.bak”
$ la
rwrwr 1 student student 124 mar 6 23:55 plik.err
rwrwr 1 student student 60 mar 6 23:47 plik.ok
Usunięcie aliasu:
$ unalias la
$ la
la: nie znaleziono polecenia
Historia poleceń
bash
Większość powłok zachowuje poprzednie polecenia i pozwala się do nich
odwoływać w poleceniu bieżącym. Mechanizm ten nosi nazwę
substytucji historycznej. Substytucja historyczna dokonuje się, gdy ciąg
znaków rozpoczyna się od wykrzyknika.
!$
- ostatni element ostatniego polecenia
$ gunzip groff.1.05.tar.gz
$ tar xvf !$
tar xvf groff.1.05.tar.gz
!!
(
!:
) - powtórz ostatnie polecenie
$ ls –l /etc
….
$ !! | more
Przykład skryptu
bash
Wylistowanie 10 (lub podanej jako parametr liczby) największych
plików w drzewie podkatalogów.
#!/bin/bash
if [[ "$1" == [09]* ]]
then
for path in $*
do
if [ $path != $1 ]
then
path_list="$path_list $path"
fi
done
ls Rl $path_list | sort k 5 nr | head $1
else
ls Rl $* | grep ^ | sort k 5 nr | head 10
fi