Narzędzia użytkownika

Narzędzia witryny


Pasek boczny

so:funkcje_trap_xargs

Funkcje w powłoce

POSIX shell

Aby zdefiniować funkcję w powłoce, należy użyć składni nazwa() treść, gdzie treść powinna być złożoną komendą (np. poleceniami zamkniętymi 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

Wynik type colorEcho

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"
}

Bash

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

Ćwiczenia

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.

Obsługa sygnałów

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.

To co nie trafiło gdzie indziej

source

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).

eval i exec

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.

yes

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.

basename i dirname

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

fc

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.

Tablice w Bashu [extra]

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łe

Zwykłą tablicę o nazwie TABLICA tworzy się przez:

  • komendę: declare -a TABLICA
  • przypisanie pustej tablicy: TABLICA=()
  • przypisanie tablicy z zawartością: TABLICA=(wartość0 [wartość1]...)
  • ustawienie wartości elementu tablicy: 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

Asocjacyjne

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.

xargs i parallel

xargs

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.

GNU parallel [ekstra]

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.

so/funkcje_trap_xargs.txt · ostatnio zmienione: 2023/05/29 12:36 przez jkonczak