Laboratorium Komputerowe Progmar
Marcin Załęczny

Na stronie używamy cookies. Korzystając z witryny wyrażasz zgodę na ich wykorzystywanie.      Zamknij

Bash - programowanie

Poniższe polecenie powoduje załadowanie do zmiennych pozycyjnych ($1, $2, ...) poszczególnych składowych wyników podpolecenia polecenie. Każda składowa rozdzielona jest znakiem ze zmiennej $IFS: set -- $( polecenie ) np: set -- $( ls -l "nazwa_pliku" ) zwróci: $1=-rwxr-xr-x, $2=1, $3=mzaleczny, $4=mzleczny, itd.

Parametry pozycyjne można usunąć poleceniem: set --

Umieszcza podaną funkcję w środowisku, dzięki czemu ta funkcja jest dostępna w procesach potomnych: export -f nazwa_funkcji

Wyświetla wszystkie zmienne środowiskowe, w odróżnieniu od polecenia set nie wyświetla wyeksportowanych funkcji: printenv

Przesuwa wszystkie parametry pozycyjne o jedną pozycję w lewo. Parametr $1 zostaje utracony, parametr $2 staje się parametrem $1, parametr $3 staje się parametrem $2, itd.: shift

Przesuwa parametry pozycyjne o podaną liczbę w lewo. Pierwsze numer parametrów zostaje utraconych: shift numer

Kończy działanie bieżącego skryptu z kodem zakończenia równym numer: exit numer

Sprawdza czy w bieżącym katalogu istnieje katalog lub plik "nazwa": test -a nazwa

Sprawdza czy w bieżącym katalogu istnieje specjalny plik blokowy nazwa_pliku: test -b nazwa_pliku

Sprawdza czy w bieżącym katalogu istnieje specjalny plik znakowy nazwa_pliku: test -c nazwa_pliku

Sprawdza czy w bieżącym katalogu istnieje katalog nazwa_katalogu: test -d nazwa_katalogu

Sprawdza czy w bieżącym katalogu istnieje katalog lub plik "nazwa": test -e nazwa

Sprawdza czy w bieżącym katalogu istnieje plik regularny nazwa_pliku: test -f nazwa_pliku

Sprawdza czy w bieżącym katalogu istnieje plik nazwa_pliku i czy ma ustawiony bit set-group-id: test -g nazwa_pliku

Sprawdza czy w bieżącym katalogu istnieje dowiązanie symboliczne nazwa: test -h nazwa lub test -L nazwa

Sprawdza czy w bieżącym katalogu istnieje plik "nazwa_pliku" i czy ma ustawiony sticky-bit: test -k nazwa_pliku

Sprawdza czy w bieżącym katalogu istnieje potok nazwany (FIFO) "nazwa": test -p nazwa

Sprawdza czy w bieżącym katalogu istnieje katalog lub plik "nazwa" i czy można z niego czytać: test -r nazwa

Sprawdza czy w bieżącym katalogu istnieje plik nazwa_pliku i czy ma rozmiar większy od 0: test -s nazwa_pliku

Sprawdza czy podany numer deskryptora "deskryptor_numer" jest otwarty i powiązany z terminalem (klawiaturą bądź ekranem): test -t deskryptor_numer

Sprawdza czy w bieżącym katalogu istnieje plik nazwa_pliku i czy ma ustawiony bit set-user-id: test -u nazwa_pliku

Sprawdza czy w bieżącym katalogu istnieje katalog lub plik "nazwa" i czy można do niego zapisywać dane: test -w nazwa

Sprawdza czy w bieżącym katalogu istnieje katalog lub plik "nazwa" i czy można go uruchomić: test -x nazwa

Sprawdza czy w bieżącym katalogu istnieje katalog lub plik "nazwa" i czy jego właścicielem jest efektywny group id: test -G nazwa

Sprawdza czy w bieżącym katalogu istnieje plik "nazwa_pliku" i czy zmienił się on od czasu ostatniego odczytu: test -N nazwa_pliku

Sprawdza czy w bieżącym katalogu istnieje katalog lub plik "nazwa" i czy jego właścicielem jest efektywny user id: test -O nazwa

Sprawdza czy podane dwa pliki znajdują się w tym samym systemie plików i odwołują się do tego samego numeru i-węzła: test plik1 -ef plik2

Sprawdza czy plik1 jest nowszy od plik2 (według daty modyfikacji) lub czy plik1 istnieje a plik2 nie: test plik1 -nt plik2

Sprawdza czy plik1 jest starszy od plik2 (według daty modyfikacji) lub czy plik2 istnieje a plik1 nie: test plik1 -ot plik2

Sprawdza czy podana zmienna została ustawiona: test -v nazwa_zmienej

Sprawdza czy łańcuch znaków "string" jest pusty (ma zerową długość): test -z string

Sprawdza czy łańcuch znaków "string" ma niezerową długość: test -n string

Zwraca true jeśli zawartość zmiennych $zmienna1 i $zmienna2 jest identyczna, false w przeciwnym razie: test "$zmienna1" == "$zmienna2" lub test "$zmienna1" = "$zmienna2"

Zwraca true jeśli zawartość zmiennych $zmienna1 i $zmienna2 jest różna, false w przeciwnym razie: test "$zmienna1" != "$zmienna2"

Zwraca true jeśli łańcuch znaków $zmienna1 wystąpi podczas sortowania wcześniej niż $zmienna2, false w przeciwnym razie: test "$zmienna1" < "$zmienna2"

Zwraca true jeśli łańcuch znaków $zmienna1 wystąpi podczas sortowania później niż $zmienna2, false w przeciwnym razie: test "$zmienna1" > "$zmienna2"

Zwraca true, jeśli obie zmienne liczbowe są równe: test $zmienna1 -eq $zmienna2

Zwraca true, jeśli obie zmienne liczbowe są różne: test $zmienna1 -ne $zmienna2

Zwraca true, jeśli zmienna liczbowa $zmienna1 jest mniejsza niż zmienna liczbowa $zmienna2: test $zmienna1 -lt $zmienna2

Zwraca true, jeśli zmienna liczbowa $zmienna1 jest mniejsza lub równa niż zmienna liczbowa $zmienna2: test $zmienna1 -le $zmienna2

Zwraca true, jeśli zmienna liczbowa $zmienna1 jest większa niż zmienna liczbowa $zmienna2: test $zmienna1 -gt $zmienna2

Zwraca true, jeśli zmienna liczbowa $zmienna1 jest większa lub równa niż zmienna liczbowa $zmienna2: test $zmienna1 -ge $zmienna2

Synonimem polecenia test są dwa nawiasy kwadratowe otoczone po lewej i po prawej stronie białym znakiem. Po nawaisie zamykającym bezpośrednio może także wystąpić średnik, np: if test -f nazwa_pliku; then jest równoważne if [ -f nazwa_pliku ]; then

Zanegowany warunek poniżej zwraca prawdę, jeśli plik nazwa_pliku nie istnieje: if [ ! -f nazwa_pliku ]; then

Instrukcja warunkowa if:

if warunek; then
    instrukcje_1
else
    instrukcje_2
fi
Rozbudowana instrukcja warunkowa if:
if warunek; then
    instrukcje_1
elif warunek_2; then
    instrukcje_2
elif warunek_3; then
    instrukcje_3
...
else
    instrukcje_n
fi

Pętla for..in:

for zmienna in lista-pozycji-rozdzielonych-znakiem-z-$IFS; do
    instrukcje
done;
Wygenerowanie listy numerowanej od wartości OD do wartości DO z krokiem inkrementującym KROK: {OD..DO..KROK} np: {1..4..1} => 1 2 3 4 oraz: {1..4..2} => 1 3 Wygenerowanie listy numerowanej od wartości OD do wartości DO z krokiem inkrementującym KROK za pomocą polecenia seq. Poszczególne pozycje są oddzielone znakiem nowej linii: seq OD KROK DO np: seq 1 1 4 => 1\n2\n3\n4\n oraz: seq 1 2 4 => 1\n3\n

Pętla for:

for (( licznik=1; licznik<=10; licznik+=2 )); do
    instrukcje
done;
Pętla po zmiennych pozycyjnych $1, $2, ...
for zmienna; do
    instrukcje
done;

Pętla while:

while warunek; do
    instrukcje
done;
Pętla ta wykonuje instrukcje tak długo jak warunek jest spełniony. Przykład użycia pętli while wykorzystanej jako miejsce docelowe potoku:
cat nazwa_pliku |
while read linia; do
    echo $linia
done;
Wypisanie podanego pliku linia po linii:
while read linia; do
    echo $linia
done <plik_tekstowy

Pętla until:

until warunek; do
    instrukcje
done;
Pętla ta wykonuje instrukcje tak długo jak warunek nie jest sepłniony.

W pętlach for, while, until można stosowć polecenia: continue oraz break.

Struktura case:

case wartosc in
    wzorzec_1)
        instrukcje_1
        ;;
    wzorzec_2)
        instrukcje_2
        ;;
    ...
    *)
        instrukcje_domyslne
        ;;
esac

Polecenie select wyświetla menu zawierające pozycje podane po słowie kluczowym in i przypisuje wybraną pozycję do zmiennej podanej po słowie kluczowym select. Następnie wykonuje polecenia pomiędzy słowami kluczowymi do i done aż do wystąpienia instrukcji break powodującego przerwanie pętli. Numer wybranej opcji zapisywany jest w zmiennej $REPLY. Znak zachęty wyboru ustawiany jest w zmiennej $PS3 (domyślnie jest to #?):

select zmienna in pozycja_1 pozycja_2 ...
do
    instrukcje
    ...
    break
done
Przykład:
#!/bin/bash

clear
select zmienna in czapka szalik rękawiczki
do
    if [ "$zmienna" == "" ]; then
        echo Nic nie wybrano
        continue
    fi

    echo $REPLY --- $zmienna
    break
done

Przekierowanie fragmentu skryptu na standardowe wejście polecenia:

#!/bin/bash

wc -l <<_KONIEC_
linijka_1
linijka_2
linijka_3
_KONIEC_
Powyższy skrypt wyświetla ilość linii przesłanych na standardwe wejście polecenia wc.

Zmienna $RANDOM generuje watość liczbową z przedziału <1..32766>

Zwiększenie zmiennej liczbowej o 1: (( i += 1 ))

Definicja funkcji:

function nazwa_f()
{
    instrukcje
}

Usunięcie funkcji nazwa_f: unset nazwa_f

Natychmiastowe opuszczenie funkcji powoduje instrukcja break. Zmienne lokalne dla funkcji definiujemy instrukcją local, np: local imie="Marcin";

Jeśli definicji zmiennej nie umieścimy po słowie kluczowym local, to jest to zmienna globalna dostępna na zewnątrz funkcji, np.: imie="Marcin";

Umieszczenie funkcji w środowisku: export -f nazwa_f Od tej pory funkcja będzie dostępna dla wszystkich procesów potomnych powłoki.

Zmienne przekazane do funkcji dosępne są w parametrach pozycyjnych, np: $1, $2, $3, ... Liczba przekazanych argumentów dostępna jest w zmiennej $#.

Funkcję:

function moja_funkcja()
{
    echo "Liczba parametrów:" $# "-" $1 $2 $3
}
wywołujemy następująco (przekazując jej argumenty): moja_funkcja 1 "param 2" 3

Otwarcie deskryptorów 3 (duplikat standardowego wejścia) i 4 (duplikat standardowego wyjścia): exec 3<&0 4>&1

Otwarcie deskryptorów 3 (plik podany w zmiennej $1 jako wejście) i 4 (duplikat standardowego wyjścia): exec 3< $1 4>&1

Otwarcie deskryptorów 3 (plik podany w zmiennej $1 jako wejście) i 4 (plik podany w zmiennej $2 jako wyjście): exec 3< $1 4> $2

Zamknięcie deskryptorów 3 i 4: exec 3<&- 4<&-

Pobranie danych z deskryptora 3 i zapisanie ich do deskryptora 4: cat <&3 >&4

Deklarowanie prostej tablicy: OWOCE=(jabłko gruszka wiśnia truskawka)

Elementy tablicy numerowane są od 0. Odwołanie do drugiego elementu tablicy: ${OWOCE[1]} - gruszka

Utworzenie duplikatu tablicy: DUPLIKAT=("${OWOCE[@]}")

Utworzenie nowej tablicy o jednym elemencie zawierającym wszystkie elementy tablicy OWOCE rozdzielone pierwszym znakiem zmiennej $IFS (zazwyczaj spacją): NOWA=("${OWOCE[*]}")

Przykład declare -a (utworzenie zmiennych typu tablicowego): declare -a DUPLIKAT='([0]="jabłko" [1]="gruszka" [2]="wiśnia" [3]="truskawka")' declare -a NOWA='([0]="jabłko gruszka wiśnia truskawka")'

Wyświetlenie liczby elementów tablicy: echo ${#OWOCE[*]}

Wyświetlenie rozmiaru podanego elementu tablicy: echo ${#OWOCE[1]}

Wyświetlenie zawartości tablicy: echo ${OWOCE[*]}

Pobiera linię od użytkownika i przypisuje ją do zmiennej linia: read -p "Podaj linię: " linia

Pobiera dwa słowa od użytkownika i przypisuje je do zmiennych slowo1 i slowo2 (jeśli słów jest więcej niż dwa, to do zmiennej slowo2 trafiają wszystkie pozostałe słowa począwszy od słowa drugiego): read -p "Podaj dwa słowa: " slowo1 slowo2

Wczytanie linii danych z podanego deskryptora pliku (tutaj 3) i przypisanie jej składowych do zmiennych slowo1 i slowo2 (zgodnie z opisaną wyżej regułą). Jeśli plik był już wcześniej otwarty i odczytywano z niego, to zaczytanie zawartości do zmiennych slowo1 i slowo2 odbędzie się począwszy od bieżącej pozycji w tym pliku: read -u3 slowo1 slowo2

Przechwycenie sygnału INT (2) i wykonanie poleceń podanych w apostrofach (wyświetlenie komunikatu i zakończenie działania skryptu z kodem 1): trap 'echo Skrypt odebrał sygnał INT. Przerywam działanie skryptu; exit 1' INT

Wykonuje podane polecenia sprzątające po zakończeniu działania skryptu (albo po bezpośrednim wywołaniu komendy exit albo po wykonaniu ostatniego polecenia w skrypcie): trap 'posprzątaj_przed_wyjściem' EXIT

Polecenie getopts przetwarza opcje przekazane w linii poleceń do skryptu: getopts [:]opcje biezaca_opcja np.: getopts :u:h:d opt

Argument opcje jest ciągiem liter które można przekazać skryptowi w formie opcji. Jeśli ciąg opcji zaczyna się od dwukropka to obsługa błędów (przekazanie do skryptu nieobsługiwanej opcji lub brak argumentu dla danej opcji) zostanie zcedowane skryptowi. Jeśli po literze opcji występje znak :, to ta opcja pobiera argument.
Parametr biezaca_opcja (w powyższym przykładzie opt) w każdym wywołaniu polecenia getopts przyjmuje kolejną literę opcji. Dodatkowo w każdym przebiegu ustawiane są zmienne OPTIND (numer opcji zaczynając od 1) oraz opcjonalnie OPTARG, która przechowuje argument dla tej opcji (o ile pobiera ona dodatkowy argument).

Poniżej znajduje się przykład przetwarzania opcji w skrypcie:

USER=
HOME_DIR=
DATE=0

while getopts :u:h:d opt; do
    case $opt in
        u) if [ -z "$OPTARG" ]; then
               echo "Nie podano nazwy użytkownika" >&2
               exit 1
           else
               USER="$OPTARG"
           fi
           ;;
        h) if [ -d "$OPTARG" ]; then
               HOME_DIR="$OPTARG"
           else
               echo "Podany katalog nie istnieje" >&2
               exit 1
           fi
           ;;
        d) DATE=1 ;;
        :) echo "Opcja $OPTARG wymaga podania argumentu" >&2
           exit 1
           ;;
        \?) echo "Nieprawidłowa opcja $OPTARG" >&2
            exit 1
            ;;
    esac
done
    
echo "Użytkownik $USER"
echo "Katalog domowy: $HOME_DIR"
if [ $DATE -eq 1 ]; then
    echo -n "DATA: "
    date
fi

Jeśli nie podano argumentu opcji (:) lub podano niedozwoloną opcję (\?), to zmienna $OPTARG przyjmuje nazwę tej opcji.

Obliczanie wyrażeń arytmetycznych: let "WARTOSC=ZMIENNA_1 + ZMIENNA_2 * 2" lub równoważnie: ((WARTOSC=ZMIENNA_1 + ZMIENNA_2 * 2)) W poleceniu let oraz w poleceniu nawiasowym nie trzeba podawać zmiennych z prefiksem $.

Do obliczania wyrażeń logicznych stosuje się składnię: [[ wyrażenie ]] Wewnątrz wyrażenia wszystkie zmienne muszą być prefiksowane znakiem $, np:

if [[ 1 < $liczba && $liczba < 10 ]]; then
    echo liczba z przedziału [2,9]
fi
Spacje wokół nawiasów [[ oraz ]] są wymagane.

Sprawdzenie czy podany tekst pasuje do wzorca (wszystkie spacje w poniższym wyrażeniu są wymagane): [[ "TEKST_LUB_ZMIENNA" = M* ]] np. IMIE=Marcin
[[ "$IMIE" = M* ]]
zwróci prawdę, podczas gdy [[ "$IMIE" = m* ]] lub [[ "$IMIE" = a* ]] zwrócą fałsz.

Usunięcie dopasowań prefiksowych i postfiksowych ze zmiennej:

#  - usuwa minimalny dopasowany przedrostek
## - usuwa maksymalny dopasowany przedrostek
%  - usuwa minimalny dopasowany przyrostek
%% - usuwa maksymalny dopasowany przyrostek
Przykłady: EMAIL=mzaleczny@jakas.domena.pl
echo ${EMAIL#m*@} => jakas.domena.pl
echo ${EMAIL#m*.} => domena.pl
echo ${EMAIL##m*.} => pl
echo ${EMAIL%.*} => mzaleczny@jakas.domena
echo ${EMAIL%%.*} => mzaleczny@jakas

Zwraca długość łańcucha znaków: echo ${#EMAIL} => 25

Wyłącza wyświetlanie na ekranie wpisywanych z klawiatury danych: stty -echo

Włącza wyświetlanie na ekranie wpisywanych z klawiatury danych: stty echo