BashBash jest jednym z najpopularniejszych interpretatorów poleceń (jest on oparty na składni sh), podobnie jak inne umożliwia on zarówno pracę interaktywną (wydawanie kolejnych poleceń przez operatora systemu), jak i pracę w trybie wsadowym (czyli wykonywanie skryptów powłokowych, stanowiących zapisane w pliku tekstowym ciągi poleceń). Praca interaktywnaPraca interaktywna polega na wprowadzaniu ciągu poleceń (przy pomocy jakiejś formy klawiatury), które są wykonywane i ich wyniki widoczne są w postaci zmian w plikach/systemie plików lub w postaci komunikatów wyświetlanych na ekranie. Normalnie odpalony
standardowe wejście wyjście i przekierowaniaDo przekierowywania wejść i wyjść poleceń służą znaki: łączenie poleceńDo łączenia poleceń oprócz przekierowywania wejść i wyjść służą także inne znaki:
Polecenia możemy także grupować przy pomocy nawiasów klamrowych sterowanie procesamiW systemach unixowatych z uruchomionymi procesami możemy komunikować się m.in. przy pomocy sygnałów. Do ich wysyłania służy program działanie w tleCelem uruchomienia polecenia w tle podajemy na końcu linii poleceń znak &. Listę tak uruchomionych zadań z aktualnego shela możemy wyświetlić poprzez polecenie sztuczki z *[]$()?Warto też wspomnieć o możliwości korzystania ze znaków wieloznacznych: * - dowolny ciąg znaków niezaczynający się od kropki, ? - dowolny jeden znak, [-xawA-F] - dowolny ze znaków wymienionych : -, x, a, w oraz przedział od A do F. Aby podejrzeć jakie pliki zostaną dopasowane do naszego wzorca polecam Jest także możliwość przekazania wyniku polecenia jako parametru innego polecenia: Kolejną sztuczką jest wbudowane przetwarzanie napisów przy pomocy Programowanie w Bash'uPraca w trybie wsadowym polega na wykonywaniu zapisanego w pliku tekstowym ciągu poleceń. Istnieje kilka metod wykonania takiego pliku:
Skrypty często mają rozszerzenia Pisanie skryptów bashowych jest w zasadzie typowym programowaniem (i wbrew pozom ten język programowania ma ogromne możliwości i wiele zagadnień można rozwiązać w nim bardzo łatwo i szybko). Program taki korzysta z dowolnych instrukcji powłoki (cd, ...) oraz wywołań innych programów (cp, rm, gawk, grep, ...). W śród wywoływanych zewnętrznych programów na szczególną miejsce zasłużył sobie (g)awk, będący interpretowanym językiem programowania służącym do przetwarzania tekstów. Z kolei wśród poleceń wbudowanych powłoki jest bardzo wiele instrukcji przeznaczonych głównie dla skryptów (aczkolwiek każdą z nich można wykorzystać w trybie interaktywnym). W tym miejscu warto także wspomnieć o pakietach takich jak zmienneJak w każdym przyzwoitym języku programowania możemy korzystać ze zmiennych. Na wstępie warto wspomnieć o paru parametrach (jest ich trochę więcej) do których dostęp mamy prze $:
Prawie wszystkie zmienne w bashu mają zasięg globalny. Wyjątkiem są zmienne odpowiedzialne za przechowywanie argumentów skryptu / funkcji (każda funkcja ma swój niezależny zestaw i nie ma dostępu do argumentów skryptu) oraz zmienne definiowane przy pomocy słowa kluczowego local przed nazwą zmiennej. Kolejnym wyjątkiem są zmienne przekazywane do podprocesów - są one w nich dostępne, ale ich zmiany nie są widoczne w głównym skrypcie - np. (odkomentowanie linii z ps pokazuje dlaczego tak się dzieje): zm=1 #ps x -l | tail echo -e "ttt\nooo" | while read f; do let zm++ echo " $zm" #ps x -l | tail done echo $zm Dostępne są też zmienne środowiskowe - takie jak $HOME czy też $PATH, a także np. pseudozmienna $RANDOM zwracająca losową liczbę. Przydatna jest także komenda Możliwe jest także (na co najmniej 3 sposoby) wydobycie zawartości zmiennej, której nazwę mamy w innej zmiennej: A="to chcemy wyświetlić"; B=A;
# metoda pierwsza
C=${!B}; echo $C
# metoda druga
C='eval "echo \$$B"'; D=`eval "$C"`; echo $D
# metoda trzecia
C=$(C='eval "echo \$$B"'; eval $C); echo $C#!/bin/bash # to jest komentarz ala="ma kota" wiek_kota=5 # powyzej zdefiniowalismy dwie zmienne, wazne aby miedzy nazwa a = nie bylo spacji echo "Ala $ala, który ma $wiek_kota lat" # oraz podstawiliśmy je - służy do tego operator $ # tutaj też uwaga odnośnie różnych cudzysłowów: # "" - zmienne są podstawiane itp, '' - tekst nie jest modyfikowany, # `` - służy do wykonania polecenia, którego stdout może być zapisany w zmiennej # w Bashu takie samo działanie ma $() ta metoda może być zagnierzdzana # (jak w poniższym przykładzie): wynik=`ls $HOME` # tutaj widzimy też że w ten sam sposób możemy obsługiwać zmienne środowiskowe ... # warto także zaznaczyć że aby zmienić zmienne środowiskowe tak aby zmiany były # widoczne poza skryptem po nadaniu nowej wartości zmiennej nalezy skorzystać z # komendy: export $ZMIENNA echo "${ala}makota" # klamerkami zaznaczyliśmy co jest nazwa zmiennej a co napisem ... echo ${nie_ma_takiego:-"Hello World"} # wypisze $nie_ma_takiego gdy ustawiony i niepusty albo (w przeciwnym razie) "Hello World" # gdy zamiast :- użyjemy := dodatkowo zmienna nie_ma_takiego zostanie ustawiona na "Hello World" # jest jeszcze pare ciekawych zastosowań ${} ... echo ${ala:+"Hello World"} # podobnie jak powyżej, ale wypisze "Hello World" gdy $ala jest zdefiniowana (nie pusta) # w przeciwnym razie użyje napisu pustego, # gdy w powyższych pominiemy : zdeklarowany napis pusty będzie rozróżniany od wartości niezdeklarowanej echo ${#ala} # wypisze długość napisu w zmiennej ala abc="abcdefgh" echo ${abc#"ab"} ${abc#"h"} ${abc:1} ${abc:2:2} # wypisze $abc: # z odrzuconym początkowym ab # końcowym h # od pozycji 1 (pierwsza litera to pozycja 0) # 2 litery od pozycji 2 ${abc:0:$[ ${#abc} - 1 ]} # powyższa dziwna konstrukcja służy wypisaniu zawartości zmiennej bez ostatniego znaku abc="abcdeabcf" echo ${abc/ab/AB} ${abc//ab/AB} # wypisze $abc z zastąpionym pierwszym (a potem wszystkimi) wystąpieniami ab przez AB # jeżeli napis dopasowywany rozpoczniemy od # musi on być na początku zmiennej # jeżeli od % musi być na końcu # podobne rzeczy można robić korzystając z expr - w szczególności # expr match $zmienna 'wyrazenieregularne1\(podwyrazenie\)wyrazenieregularne2' # zwróci część podanej zmiennej pasującej do podanego podwyrażenia ujętego w \( \) expr $abc : '.*\([^df]*\)' # możemy używać $ wewnątrz napisów - w tym celu zabezpieczmy go \ lub napis umieszczmyu w '' xx='${ala} ma $HOME' ala="ALA" export ala echo $xx # jak widać zmienne wtedy nie są podmieniane, ale jeżeli wyeksportujemy zmienną # i przekażemy taki napis do envsubst to zostaną podstawione echo $xx | envsubst # możemy nawet określić które mają być podstawiane ... echo $xx | envsubst '$ala' # ale to jeszcze nie wszystko bash umożliwia nam kozystanie z TABLIC: tablica[0]="to jest element 0" tablica[1]="to jest element 1" element=1 echo ${tablica[1]} " --- " ${tablica[0]} # @ i * zachowują się tak jak w $@ i w $* ... echo ${tablica[@]} echo ${#tablica[@]} # zwróci ilość elementów w tablicy, ale echo ${#tablica[1]} # zwróci długość elementu o indeksie 1 # pozostałe operacje napisowe gdy są stosowane do ${tablica[@]} stosują się do # całej zawartości tablicy a gdy ${tablica[$i]} do elementu określonego w $i ... XHTML generated by highlight 2.4.5 (http://www.andre-simon.de/) from zmienne.sh pętle i instrukcje wyboruDo dyspozycji mamy także pętle oraz instrukcje wyboru. W śród pętli warto zwrócić uwagę iż mogą one funkcjonować w oparciu o warunek zawarty w nawiasach kwadratowych lub też na liście plików / słów, czy też do czasu aż jakaś komenda się wykonuje. #!/bin/bash for nazwa in /tmp/* ; do echo $nazwa; done # powyzsza petla wypisze nazwy wszystkich plików znajdujących się w /tmp for (( i=0 ; $i<=20 ; i++ )) ; do echo $i; done # powyzsza petla wypisze liczby od 0 do 20 cat /etc/fstab | while read slowo reszta_linii; do echo $reszta_linii; done # powyższa pętla wypisze po kolei wszystkie wiersze pliku przekazanego przez stdin # (cat nazwa_pliku |) z pominięciem pierwszego słowa (pierwsze słowo wczytywane było # do zmiennej slowo, której nie wypisywaliśmy) jest też pętla until która odpowiada # while z zanegowanym warunkiem (w tym wypadku warunkiem jest instrukcja read) XHTML generated by highlight 2.4.5 (http://www.andre-simon.de/) from for.sh Dość praktycznym zastosowaniem pętli w bashu jest wywoływanie czegoś dla każdej linii wejścia - np.
Więcej informacji o warunkach jakie możemy zawrzeć w [] wykorzystywanym zarówno w pętlach jak i warunkach typu if patrz: #!/bin/bash # ponizszy wpis wlacza wypisywanie wykonywanych polecen #- bardzo przydatne przy debugowaniu skryptow ... set -x COS="ryba"; # poniższy fragment obrazuje instrukcje case na prostym przykładzie case $COS in kot | pies) echo "kot lub pies" ;; ryba) echo "ryba" ;; *) echo "cos innego" ;; esac # następny fragment działa dokładnie tak samo tyle że na instrukcji if if [ "$COS" = "kot" -o "$COS" = "pies" ]; then echo "kot lub pies"; elif [ "$COS" = "ryba" ]; then echo "ryba" else echo "cos innego" fi XHTML generated by highlight 2.4.5 (http://www.andre-simon.de/) from case_if.sh funkcjeBash umożliwia również definiowanie funkcji, z których możemy potem korzystać jak z zwykłych poleceń: #!/bin/bash # deklaracja funkcji o nazwie wypisz, argumenty podstawiane są jako $1 $2 ... function wypisz() { echo "$1 World !!!" } # wywolanie funkcji petla z jednym argumentem - Witaj wypisz Witaj XHTML generated by highlight 2.4.5 (http://www.andre-simon.de/) from function.sh skrypty z opcjamiPrzy zastosowaniu narzędzi takich jak #!/bin/bash # przetworzenie argumentów określonych w wywołaniu getopt # dalsze argumenty dostępne są w $1, $2, itd po zakończeniu pętli # : -> poprzedzająca opcja wymaga argumentu # :: -> poprzedzająca opcja może mieć argument # uwaga o ile wymagane argumenty moga byc rozdzielane od opcji spacją o tyle opcjonalne nie # (krótkie należy podawać zaraz po opcji, długie rozdzielając =) eval set -- "`getopt -o xy:z:: -l opcja-x,opcja-y:,opcja-z:: -- "$@"`" while true; do case $1 in -x|--opcja-x) echo "X";; -y|--opcja-y) echo "Y, argument \`$2'"; shift;; -z|--opcja-z) echo "Z, argument \`$2'"; shift;; # tuataj $2 może być pusty (gdy nie podano), ale jest zdefiniowany --) shift; break;; esac shift; done XHTML generated by highlight 2.4.5 (http://www.andre-simon.de/) from opcje.sh Linki i moje projektyZachęcam również do przyjrzenia się kilku prostym skryptom bashowym:
Polecam także zajrzeć do artykułu poświęconego językowi AWK, który jest bardzo użyteczny w połączeniu z bash'em. Więcej informacji o Bash'u: | |
|
|
Copyright (c) 1999-2008, Robert Paciorek (http://www.opcode.eu.org/), BSD-type license
Redystrybucja wersji źródłowych i wynikowych, po lub bez dokonywania
modyfikacji JEST DOZWOLONA, pod warunkiem zachowania niniejszej informacji o
prawach autorskich. Autor NIE ponosi JAKIEJKOLWIEK odpowiedzialności za skutki
użytkowania tego dokumentu/programu oraz za wykorzystanie zawartych tu informacji.
This program is free software. Redistribution and use in source and binary
forms, with or without modification, ARE PERMITTED provided save this copyright
notice. This document/program is distributed WITHOUT any warranty, use at YOUR
own risk.
Dokument ten (URL: http://www.opcode.eu.org/bash)
należy do serwisu OpCode. Autorem tej strony jest Robert Paciorek,
wszelkie uwagi proszę kierować na adres e-mail serwisu: webmaster@opcode.eu.org.
Data ostatniej modyfikacji artykulu: 2008-08-24 17:58:33 (UTC) (data ta może być zafałszowana niemerytorycznymi modyfikacjami artykułu).