Skrypty

Popularne interpretery

  • sh — (Bourne shell) szeroko dostępny interpreter
  • bash — (Bourne-again shell) rozszerzona wersja sh
  • fish — (Friendly Interactive shell) interpreter z ułatwieniami dla użytkowników i programistów
  • csh and tcsh — (C shell) interpreter luźno oparty na składni języka C
  • zsh — (Z shell) rozszerzona wersja bash-a

Wykonywanie skryptów

Lista komend zapisana w dowolnym pliku tekstowym może być wykonana za pomocą intepretera:

  • sh PLIK
  • bash PLIK

Pliki wewnętrznie oznacza się jako skrypt podając w pierwszej lini pliku dyrektywę interpretera która informuje system operacyjny za pomocą jakiego polecenia je otworzyć. Dyrektywa to pełna ścieżka programu do wykonania poprzedzona znakiem komentarza i wykrzyknikiem #! (tzw. shebang):

  • #!/bin/sh
  • #!/bin/bash

Można w ten sposób oznaczyć dowolny plik tekstowy do otwarcia za pomocą dowolnego programu:

  • #!/usr/bin/env python
  • #!/usr/bin/firefox

Plik tekstowy oznaczony dyrektywą można uruchomić:

  • ./SKRYPT.sh – w katalogu bieżącym
  • /home/user/SKRYPT.sh – pełna ścieżka (z dowolnego katalogu)

Żeby uruchomić plik należy mu nadać odpowiednie prawa (chmod).

Parametry i zmienne

Skrypt może zostać uruchomiony z argumentami, np.:

./SKRYPT.sh a b c d

Argumenty są dostępne przez parametry pozycyjne (positional parameters):

$1 $2 $3 $4 ... ${10} ${11} ...

Polecenie shift n przesuwa zawartość zmiennych o n w lewo (domyślnie n = 1).

Przykłady::
shift # 1=$2, 2=$3, 3=$4 ... shift 2 # 1=$3, 2=$4, 3=$5 ...

Zmienne specjalne

  • $0 – ścieżka do skryptu (nazwa wykonywanego skryptu)
  • $# – liczba argumentów
  • $* – wszystkie parametry pozycyjne jako jeden napis ("$1 $2 ..."
  • $@ – wszystkie parametry pozycyjne jako osobne napisy ("$1" "$2" ...)
  • $$ – PID procesu skryptu

Tablice

Definicja:

array[0]=asia
array[1]=basia
array[2]=casia
array[a]=asia
array[b]=basia
array[c]=casia

Definicja całej tablicy:

array2=( asia basia casia )
array3=([0]=asia [0]=basia [0]=casia)               # only int->whatever

Odczyt konkretnego elementu:

echo ${array[b]}

Wszystkie elementy tablicy:

echo ${array[@]}
echo ${array[*]}

Długość tablicy:

echo ${#array[@]}
echo ${#array[*]}

Kontrola zmiennych

Polecenia declare i typeset:

declare -r x=5        # deklaracja zmiennej tylko do odczytu
echo $r
r=6

declare -i y          # deklaracja zmiennej o typie l. całkowita
y=5
echo $z

y="ala ma kota"
echo $z

declare -a arr        # deklaracja tablicy

Komentarze

Komenatrze zaczynają się od znaku # i kończą się wraz z końcem bieżącej lini.

# Prawo Ohma
I=`expr $V / $R`
#echo "I=$V/$R -> $I"

# TODO Dodać prawo Kirchhoffa

Jakie zastosowania mają komentarze?

Konstrukcje językowe

Separatory instrukcji

Sposoby wykonania dwóch komend:

# wykonanie sekwencyjne
COMMAND1
COMMAND2

# wykonanie sekwencyjne
COMMAND1; COMMAND2

# wykonanie warunkowe
COMMAND1 && COMMAND2

# wykonanie warunkowe
COMMAND1 || COMMAND2

# wykonanie współbieżne
COMMAND1 & COMMAND2

# potok
COMMAND1 | COMMAND2

Konstrukcja if

if COMMAND0
then
    INSTRUCTIONS
elif COMMAND1           # Opcjonalne
    INSTRUCTIONS
else                    # Opcjonalne
    INSTRUCTIONS
fi

Wykonywane instrukcje w zależności od stanu wykonania wskazanej komendy COMMAND0.

Przydatne polecenia:

  • false – nie robi niczego i kończy się stanem 1
  • true – nie robi niczego i kończy się stanem 0
  • test – sprawdza wskazany warunek
  • [ ] – j/w tylko krócej
  • (( )) – sprawdza warunek arytmetyczny.
  • $(( )) – wykonuje działanie arytmetyczne

Konstrukcja case

case VALUE in
    PATTERN0) INSTRUCTIONS;;             # lub ;&
    PATTERN1) INSTRUCTIONS;;             # lub ;&
    PATTERN2) INSTRUCTIONS;;             # lub ;&
    PATTERN3) INSTRUCTIONS;;             # lub ;&
esac

Możliwa dowolna liczba warunków i dowolny blok instrukcji po każdym z warunków.

Przy zastosowaniu ;; po przypasowaniu do warunku i wykonaniu instrukcji wychodzi z konstrukcji case. Przy zastosowaniu ;& wykonuje instrukcje także kolejnego warunku.

Przykłady warunków:
  • napis – traktowany dosłownie
  • * – dowolny ciąg znaków
  • [A-Z] – klasa znaków
  • ? – dowolny znak
  • image_199[0-9]\*.jp?g – złożony warunek

Pętla while

while COMMAND
do
    INSTRUCTIONS
done

Wykonywane instrukcje do czasu az stan wykonania komendy COMMAND będzie inny od 0.

Przydatne instrukcje (dla każdego rodzaju pętli):

  • break – przerywa działanie pętli
  • continue – przerywa wykonywanie instrukcji w ciele pętli i przechodzi do następnej iteracji

Pętla for

for VARIABLE_NAME in ARGUMENT_LIST
do
    INSTRUCTIONS
done

Wykonuje instrukcje dla każdego z argumentów z ARGUMENT_LIST. Każdy z argumentów jest przypisywany kolejno do zmiennej VARIABLE_NAME.

Alternatywna uproszczona składnia:

for VARIABLE_NAME
do
    INSTRUCTIONS
done

Wykounje instrukcje dla każdego z argumentów (parametrów pozycyjnych) skryptu.

Pętla for à la C

for (( INIT_EXPR ; TEST_EXPR ; STEP_EXPR ))
do
    INSTRUCTIONS
done

Gdzie: INIT_EXPR jest wykonane przed pętlą, TEST_EXPR jest wykonywane przed każdą iteracją i wynik zwracany przez wyrażenie ($?) powoduje rozpoczęcie iteracji lub zakońćzenie pętli, STEP_EXPR to wyrażenie wykonywane po każdej iteracji.

(( INIT_EXPR ))
while (( TEST_EXPR ))
do
    INSTRUCTIONS
    (( STEP_EXPR ))
done

Pętla select

select VAR in ARGUMENT_LIST
do
    INSTRUCTIONS
done

Zakończenie działania skryptu

exit
Zakończ wykonywanie skryptu. Jako argument przyjmuje stan zakończenia. Domyślnie status 0.

Operacje wejścia/wyjścia

read

Wczytaj do zmiennej. (BASH shell bultin)

-p prompt znak (napis) zachęty
-t timeout czas wygaśnięcia w sekundach
-s nie wyświetlaj znaków wpisanych przez użytkownika
# Najprostszy przypadek
read i
echo $i

# Hasło wpisywane bez echa, max. przez 30 sekund
read -p "Password: " -s  -t 30 password
echo $password

Funkcje

function NAME () {      # Opcjonalne "function" lub "()"

    INSTRUCTIONS

} REDIRECTION           # Opcjonalne "REDIRECTION"

Przykłady:

# Przekierowuje echo na STDERR
function echo_err {
    echo $@
} >&2

echo_err "Ala ma kota"

# Przeciąża polecenie echod
function echo {
    if $DEBUG
    then
        echo $@
    fi
}

# Sprawdza warunek i ustawia stan wyjścia
function fsm_spaghetti_day {
    if [ `date +%A` == 'Friday' ]
    then
        exit 0
    fi
    exit 1
}

Ankieta SOP

Ankieta RSOCR

Zadania

  1. Skrypt tworzący nazwę projektu, zmiennej, itp. wg określonego formatu.

    Jako pierwszy parametr podajemy nazwe formatu docelowego,

    Przykłady użycia:
    • ./chcase joined    my new project     # Zwraca: mynewproject
    • ./chcase underline my new var         # Zwraca: my_new_project
    • ./chcase uppercase my new const       # Zwraca: MY_NEW_CONST
    • ./chcase dashes    my new resource    # Zwraca: my-new-resources

    Jeśli format nie zostanie podany wyświetl dostępne formaty i zakończ z błędem. Jeśli użytkownik nie poda argumentów, wyświetl krótką instrukcję i zakończ z błędem.

  2. Skrypt tworzacy kopie zapasowe wskazanych plików i katalogów. Jako pierwszy

    parametr należy podać miejsce utworzenia kopii. Jako kolejne podajemy nazwy kopiowanych plików i katalogów. Do nazw kopiowanych zasobów dodana powinna być też data i czas utworzenia kopii.

    Przyklad użycia:

    ./bup /tmp/backup asia/ basia/ casia.txt

    Spowoduje powstanie plików:
    • /tmp/backup/10-05-12_10:03_asia/
    • /tmp/backup/10-05-12_10:03_asia/cokolwiek_było_w_katalogu
    • /tmp/backup/10-05-12_10:03_basia/
    • /tmp/backup/10-05-12_10:03_basia/cokolwiek_było_w_katalogu
    • /tmp/backup/10-05-12_10:03_casia.txt

    Jeśli wskazany katalog docelowy nie istnieje to należy go utworzyć. Jeśli wskazany katalog docelowy istnieje ale nie jest katlogiem, należy zakończyć działanie z błędem.

    Jeśli plik do kopiowania nie istnieje, należy go pominąć i na samym końcu działania programu wypisać ostrzeżenie, że plik nie został odnaleziony.

  3. Skrypt który rozmawia z użytkownikiem. Użytkownik zadaje pytanie, skrypt losuje odpowiedź z pliku. Kiedy użytkownik napiszę kluczową frazę (np. that's enough) skrypt kończy rozmowę.

  4. Skrypt który czeka, aż zawartość określonej strony się zmieni. Jeśli zawartość się zmieniała, to skrypt wykonuje wskazaną komendę. Użytkownik może (ale nie musi) określić jak często skrypt ma sprawdzać kopie lokalną.

    Przykład użycia:

    # Przykładowa strona (zapisana do zmiennej dla wygody)
    WEBSITE=http://www.cs.put.poznan.pl/ksiek/SOP/resources/embrace_change.php
    
    # Sprawdza czy strona się zmieniła z domyślną częstotliwością.
    # Jeśli strona się zmieni to otwiera ją w przeglądarce internetowej.
    ./diditchange "$WEBSITE" firefox "$WEBSITE"
    
    # Sprawdza czy strona się zmieniła raz na 5 sekund.
    # Jeśli strona się zmieni to otwiera ją w przeglądarce internetowej.
    ./diditchange "$WEBSITE" -t 5 firefox "$WEBSITE"
    

    Jeśli nie można połączyć się ze stroną skrypt powinien wyświetlić błąd i zakończyć działanie.

    Przydatne polecenia: wget, sleep.

  5. Skrypt-predykat który sprawdza porę dnia. Możliwe pory dnia: early, late, day, night, morning, lunchtime, evening

    Przykłady użycia:

    if ./its late
    then
       ...
    fi
    
    while ./its lunchtime
    do
       ...
    done
    

    Jeśli użytkownik poda porę dnia nieznaną skryptowi należy wyświetlić komunikat o błędzie.

  6. Skrypt który dodaje dyrektywę interpretera dla skryptów znalezionych we wskazanych katalogach. Do skryptów o rozszerzeniu .sh dodawane jest #!/bin/bash, do skryptow o rozszerzeniu .py ‘#!/usr/bin/env python’. Inne rodzaje skryptów są pomijane.

    Przykład użycia: ./addshebang repository/scripts "/tmp/work in progress"

    Jeśli plik już posiada dyrektywę interpretera, wypisz wiadomość do użytkownika i zignoruj plik.

Na pocieszenie

Nobody really knows what the Bourne shell’s grammar is.
Even examination of the source code is little help.
http://en.wikipedia.org/wiki/Tom_Duff