Dydaktyka:
FeedbackTo jest stara wersja strony!
Aby zdefiniować funkcję w powłoce, należy użyć składni
nazwa() treść
, gdzie treść powinna być złożoną komendą
(np. ciągiem poleceń zamkniętych w { … }
).
Wywołanie takiej funkcji realizuje się przez nazwa [argument]...
, przy
czym wewnątrz funkcji zmienne $#
oraz $1
, $2
, ... dotyczą właśnie
argumentów funkcji.
Wewnątrz funkcji można też używać polecenia return [n]
które kończy funkcję
zwracając wartość n lub, jeśli nie podano n, wartość $?
.
Dla funkcji nazwa polecenie type nazwa
zwróci przynajmniej informację
że nazwa jest funkcją, a w Bashu dodatkowo wyświetli jej ciało (podobnie jak
komenda declare -f nazwa
).
Przykład:
user@host ~ $ colorEcho() { > case "$1" in > red) CCODE=31;; > green) CCODE=32;; > blue) CCODE=34;; > *) CCODE=5;; > esac > echo -ne "\033[${CCODE}m"; > echo -n "$2"; > echo -e "\033[0m"; > } user@host ~ $ colorEcho red riding hood riding user@host ~ $ colorEcho green "anne of green gables" anne of green gables
user@host ~ $ type colorEcho colorEcho jest funkcją colorEcho () { case "$1" in red) CCODE=31 ;; green) CCODE=32 ;; blue) CCODE=34 ;; *) CCODE=5 ;; esac; echo -ne "\033[${CCODE}m"; echo -n "$2"; echo -e "\033[0m" } user@host ~ $
Inny przykład:
compressInDateDir() { [ $# -ge 2 ] || return 1 TARNAME="$(readlink -f "$1")" shift WORKDIR="$(mktemp -dp. || mktemp -d)" [ "$WORKDIR" ] || return 1 DATE=$(date +%Y_%m_%d) mkdir "$WORKDIR/$DATE" cp -al "$@" "$WORKDIR/$DATE" tar cJf "$TARNAME" -C "$WORKDIR" "$DATE" rm -rf "$WORKDIR" }
Powłoka Bash wprowadza parę rozszerzeń do funkcji.
Po pierwsze, w Bashu można poprzedzić funkcję słowem kluczowym function
.
Po drugie, w Bashu można deklarować lokalne zmienne wewnątrz funkcji
poprzedzając ich nazwę słowem kluczowym local
.
user@host ~ $ X=5; user@host ~ $ up() { X=$((X+$1)); echo $X; } user@host ~ $ up 1 6 user@host ~ $ up 1 7 user@host ~ $ up() { local X=$((X+$1)); echo $X; } user@host ~ $ up 1 8 user@host ~ $ up 1 8 user@host ~ $ echo $X 7
Zadanie 1
Napisz funkcję która wyświetla hello world
.
Zadanie 2 Napisz funkcję przyjmującą dwa argumenty: liczbę (ilość powtórzeń) i tekst. Funkcja ma wypisać na standardowe wyjście podany tekst podaną ilość razy.
Zadanie 3
Napisz funkcję przyjmującą jako argument nazwę pliku. Jeśli taki plik nie
istnieje, w wyniku działania funkcji taki plik ma zostać utworzony bez praw
dostępu dla grupy i pozostałych.
Możesz użyć polecenia umask
(lepsze rozwiązanie) lub chmod
(gorsze
rozwiązanie).
Zadanie 4
Napisz funkcję zastępującą program tree
: funkcja ma przeszukać w głąb (DFS)
pliki zaczynając od podanego katalogu i wypisać dla każdego pliku jego nazwę
z odpowiednimi wcięciami.
Zadanie 5 Napisz funkcję liczącą rekurencyjne silnię i wypisującą jej wynik na standardowe wyjście.
Komendą trap polecenie SYGNAŁ
można ustawić obsługę podanego SYGNAŁu oraz, podając zamiast nazwy sygnału
słowo EXIT, ustawić polecenie do wykonania bezpośrednio przed zakończeniem
procesu powłoki.
W powłoce obsługa sygnału ustawiona komendą trap
jest wykonywana
bezpośrednio po zakończeniu polecenia w trakcie którego odebrano sygnał.
Polecenie musi być podane jako ciąg tekstu.
Polecenie ustawione jako EXIT nie jest wykonywane tylko jeśli powłoka kończy
pracę w wyniku sygnału KILL lub polecenia exec
.
Składnia trap - SYGNAŁ
przywraca domyślną obsługę sygnału.
Zadanie 6
Dodaj obsługę sygnału INT (generowanego przez Ctrl+c
) do skryptu
wykonującego sleep czas
oraz echo tekst
. Porównaj przerwanie
komendy sleep
sygnałem INT z przerwaniem skryptu sygnałem INT.
Zadanie 7
Stwórz w skrypcie plik tymczasowy komendą mktemp
. Ustaw obsługę zdarzenia
wyjścia z powłoki tak, by usuwała ten plik i wyświetlała tekst.
Umieść w skrypcie komendę sleep czas
oraz echo tekst
.
• Porównaj przerwanie komendy sleep
sygnałem INT z przerwaniem skryptu sygnałem INT
• Sprawdź czy przerwanie skryptu sygnałem TERM usuwa plik.
• Sprawdź czy przerwanie skryptu sygnałem KILL usuwa plik.
Komenda . plik
(i komenda source plik
w Bashu) uruchamiają
polecenia z podanego pliku w bieżącej powłoce (tzn. tak jakby były wpisane z klawiatury).
Zadanie 8
Wpisz do pliku plik ustawienie wartości kilku zmiennym.
Wczytaj ten plik komendą .
(lub source
) i sprawdź wartości tych
zmiennych.
Zadanie 9
Wpisz do pliku plik polecenie exit
. Nadaj mu prawa do wykonywania.
Wykonaj ten plik (tzn. wykonaj ./plik
) oraz użyj komendy .
na tym pliku
(tzn. wykonaj . ./plik
).
Komenda eval
wykonuje podaną jako tekst komendę.
Komenda exec
zawierająca tylko przekierowania ustawia podane przekierowania dla powłoki (było
przy okazji przekierowań), natomiast z podaną komendą zastępuje powłokę podanym
poleceniem.
Zadanie 10
Umieść w skrypcie eval xterm
oraz echo eval
i uruchom ten skrypt.
Następnie umieść w skrypcie exec xterm
oraz echo exec
i uruchom ten skrypt.
Komenda yes [tekst]
wypisuje w kółko tekst na standardowe wyjście.
Domyślnie wypisuje tekst y
.
yes
jest używane do generowania odpowiedzi dla programów które pytają czy
na pewno chcesz...
i nie mają przełącznika który wyłącza takie pytania.
Zadanie 11
Stwórz pliki plik_1
, plik_2
, … , plik_9
.
Spróbuj je usunąć komendą rm -i plik_?
. Połącz tą komendę z komendą yes
tak żeby yes
potwierdził usunięcie plików.
Program basename ścieżka [rozszerzenie]
wypisuje na standardowe wyjście nazwę pliku
wskazanego ścieżką, opcjonalnie usuwając z nazwy rozszerzenie.
Program dirname ścieżka
wypisuje na standardowe wyjście katalog w którym znajduje się plik
wskazany ścieżką.
$(basename "$X")
i $(dirname "$X")
w wielu przypadkach można zastąpić przez ${X##*/}
i ${X%/*}
. Należy pamiętać, że basename
i dirname
, w odróżnieniu od podstawień, poradzą sobie ze zniekształconymi ścieżkami.
Zadanie 12
Przetestuj basename
i dirname
dla:
• ../../../etc/passwd
• /usr/share/icons/hicolor/
• plik
Komenda fc
tworzy plik tymczasowy, wstawia do niego poprzednią komendę z historii, otwiera
ten plik w edytorze tekstu, a po zamknięciu edytora wykonuje poprawioną komendę.
Zadanie 13
Wykonaj jakąś długą komendę (np. for X in $(grep -lR 'terminal' /usr/share/applications/); do grep "Name" $X; done
), następnie wpisz fc
, zmodyfikuj ją i wykonaj.
Poza zwykłymi zmiennymi, powłoka Bash wspiera zwykłe tablice (indeksowane kolejnymi liczbami naturalnymi) oraz tablice asocjacyjne (indeksowane tekstowymi kluczami).
Skrócony opis poniżej; pełen w podręczniku Basha.
Zwykłą tablicę o nazwie TABLICA
tworzy się przez:
declare -a TABLICA
TABLICA=()
TABLICA=(wartość0 [wartość1]...)
TABLICA[0]=wartość
Dodanie nowych elementów pod wskazany indeks realizuje się komendą
TABLICA[indeks]=wartość
, natomiast dodanie na koniec komendą
TABLICA+=(wartość1 [wartość2]...)
.
Odwołanie się do zmiennej TABLICA spowoduje:
$TABLICA
podstawi wartość elementu pod indeksem 0${TABLICA[indeks]}
podstawi wartość elementu pod indeksem indeks${TABLICA[@]}
podstawi wszystkie wartości w tablicy ${!TABLICA[@]}
podstawi wszystkie indeksy w tablicy ${#TABLICA[@]}
podstawi ilość elementów
Asocjacyjną tablicę o nazwie TABLICA
tworzy się przez komendę declare -A TABLICA
.
Dodanie nowych elementów można wykonywać przez:
TABLICA[klucz]=wartość
TABLICA+=([klucz1]=wartość1 [klucz2]=wartość2 ...)
(uwaga: tutaj [
są elementem składni)TABLICA+=(klucz1 wartość1 klucz2 wartość2 ...)
Przy czym dwie ostatnie składnie, przy zastąpieniu +=
przez =
, służą do
nadpisania tablicy podaną listą kluczy i wartości.
Odwoływanie się do tablicy asocjacyjnej jest identyczne jak dla zwykłej.
Program xargs program
czyta ze standardowego wejścia kolejne nazwy i wykonuje
program
z tymi nazwami jako argumentem.
xargs
jest głównie wykorzystywany w potokach, do uruchomienia podanego
programu z listą argumentów generowanych przez potok.
Poglądowo, np. potok | xargs program
wykonuje mniej więcej program $(potok)
,
natomiast np. potok | xargs -n1 program
wykonuje mniej więcej for ARG in $(potok); do program $ARG; done
, ale potok i program są wywoływane jednocześnie.
Domyślnie xargs program
wykonuje program wpisując na koniec listy
argumentów wszystkie przeczytane nazwy naraz.
Można określić po ile argumentów naraz
ma być wstawianych na koniec podanej komendy przełącznikiem -n
:
user@host ~ $ seq 5 | xargs echo -e 1 2 3 4 5 user@host ~ $ seq 5 | xargs -n 2 echo -e 1 2 3 4 5
Można też użyć przełącznika -I słowo
do wskazania w które miejsce linii
poleceń ma być wstawiony każdy argument (co implikuje uruchomienie komendy osobno
dla każdego argumentu):
user@host ~ $ seq 3 | xargs -I ARG echo ">>ARG<< >>ARG<<" >>1<< >>1<< >>2<< >>2<< >>3<< >>3<<
Polecenie xargs
rozdziela standardowe wejście po dowolnych białych znakach,
co powoduje problemy np. ze spacjami.
Większość implementacji polecenia xargs
rozumie przełącznik -0
rozdzielający nazwy znakiem \0
:
user@host ~ $ fortune BOFH Excuse #443: Zombie processes detected, machine is haunted. user@host ~ $ fortune | xargs -n1 echo " *" * BOFH * Excuse * #443: * Zombie * processes * detected, * machine * is * haunted. user@host ~ $ fortune | tr '\n' '\0' | xargs -n1 -0 echo " *" * BOFH Excuse #443: * Zombie processes detected, * machine is haunted.Przykładowe przełączniki dla różnych programów generujące znak
\0
do
oddzielenia kolejnych elementów opisuje nawet Wikipedia dla hasła xargs.
GNU xargs
(zwykle domyślny w Linuksie) rozumie też przełącznik -P [num]
który pozwala
uruchomić num równoległych procesów (jeśli podano -P
bez argumentów,
odpalane jest tyle procesów z ilu rdzeni można skorzystać).
Zadanie 14
Stwórz katalogi o nazwach 001
, 002
, 003
, ..., 999
używając
xargs
.
Zadanie 15
Policz sumy kontrolne MD5 dla plików *.pdf
znalezionych narzędziem
locate
w katalogu /usr/share/
.
Wykonaj to zadanie zarówno używając xargs
jak i używając pętli w powłoce.
Zadanie 16
Skopiuj pliki z katalogu /usr/include
zawierające tekst
typedef signed char
do katalogu /tmp/
używając xargs.
Komenda grep
z przełącznikiem -l
wypisuje tylko nazwy pasujących plików,
a z przełącznikiem -R
szuka rekurencyjnie.
Do uruchamiania współbieżnie m. inn. programu dla argumentów czytanych ze
standardowego wejścia można też wykorzystać program parallel. Dla tego zastosowania jest praktycznie zamiennikiem xargs
.
Z odpowiednimi argumentami parallel
pozwala też uruchamiać dowolne zadania
współbieżnie kontrolując ilość jednocześnie uruchomionych zadań.
Więcej informacji na gnu.org/software/parallel.