Opis powłoki "ksh" z manuala (z drobnymi poprawkami).
set -o emacs
# mozna wtedy wprowadzac i edytowac komendy w naturalny
sposob
# dziala historia polecen przy pomocy strzalek gora/dol
set -o vi
# niestety, w tym trybie nalezy uzywac komend edytora
"vi" !
# 2 tryby pracy :
# tryb komend i tryb wprowadzania
znakow
# przejscie do trybu komend : ESC
# przejscie do trybu wprowadzania znakow : "i", "a",
# (lub "A" - przejscie na koniec linii
!)
# w trybie komend :
"k" - poprzednia linia
"j" - nastepna linia
"h" - 1 znak w lewo
"l" - 1 znak w prawo
"x" - kasowanie znaku
"/wyr_reg" - poszukiwanie
tekstu (w poprzednio wprowadzo-
nych liniach)
oraz wiele innych uzytecznych
komend edytora "vi"
--> "skrypt"
aby mozna bylo uruchamiac skrypty
jak "progamy binarne"
nalezy:
a) w pierwszej linii
umiescic nazwe interpretera, np:
#!/bin/ksh
# reszta skryptu ...
....................
b) nadac plikowi ze
skryptem prawo "x"
chmod u+x skrypt
UWAGA:
polecenia, o ktorych mowa w dalszym ciagu
mozna takze
wyprobowac z linii polecen ...
Zadanie 33
#!/bin/cat aaaaaaaaaaaaaaaaaa bbbbbbbbbbbbbbbbbb cccccccccccccccccci uruchom go (oczywiście sposobem "z prawem x"). Wywnioskuj z tego w jaki sposób interpreter otrzymuje treść skryptu.
Zadanie 34
*** komenda
-> nazwa_komendy arg1 arg2 ...
# Przykład :
ls -l -a
ls -ld
cat plik.txt
echo "1 2" 3 4
-> rozróżniamy komendy wbudowane
w powloke i
programy (ktorych
kod znajduje sie w pliku z prawem "x")
# Przykład :
echo 123 qqq "Q W E" # komenda wbudowana
ls -l qqq
# program
-> kod zakonczenia komendy :
0 - oznacza ok,
1,2,... - zazwyczaj oznacza blad
po zakonczeniu
dzialania komendy
mozna go odczytac
przez : "echo $?"
(zmienna $?
zawiera kod zakonczenia)
# Przyklad :
rm plik.txt; echo "kod zakonczenia=$?"
# wyprobuj to polecenie gdy plik.txt istnieje i nie istnieje !
*** potok
komenda1 | komenda2 | komenda3
| ...
*** lista
potok1 <sep> potok2 <sep>
potok3 <sep> ...
gdzie <sep> to jeden z symboli
";" "&" "&&" "||"
Listy są uzywane jako "cialo" oraz "warunek" w instrukcjach.
Znaczenie symboli podwójnych ("&&"
i "||") jest takie jak w języku C:
Działanie
takich list można traktować jako
"obliczanie
wartości wyrażenia logicznego z optymalizacją"
("&&"
to koniunkcja, "||" to alternatywa).
Kod zakończenia
komend jest interpretowany logicznie:
kod=0
to "prawda", kod<>0 to "fałsz".
Optymalizacja
polega na tym, że jeśli w czasie obliczania
wartości
wyrażenia okaże się, że wartość wyrażenia jest znana
to nie
sprawdza się pozostałych składników wyrażenia
(nie uruchamia
się ich komend !).
# Przykłady list "logicznych":
true &&
echo ABC # wyswietla ABC
false
&& echo ABC # nie wyswietla
# true i false to komendy zwracajace kod zakonczenia 0 i 1
#
# w pierwszym przypadku aby poznać wartość wyrażenia
# logicznego trzeba uruchomić drugą komendę (dlatego
# napis ABC jest wyświetlany)
#
# w drugim przypadku wiadomo, że wartością tą będzie fałsz
# dlatego komenda echo nie jest uruchamiana
rm plik.txt
&& echo "Usunąlem plik !"
rm plik.txt
|| echo "Nie usunąlem pliku !"
# te przykłady działają tak jak powinny
# Przykłady list innego
rodzaju:
ls&
ls&
# oba procesy oraz powloka dzialaja rownoczesnie !
ls&
ls;
# pierwszy "ls" dziala jednoczesnie z drugim
# jednak powloka czeka na zakonczenie drugiego "ls"
ls; ls;
# polecenia są uruchamiane po kolei
# powłoka czeka na zakończenie każdego
# (koncowy ";" mozna opuszczac)
*** instrukcje sterujace
if lista; then lista; fi
if lista; then lista; [elif lista; then
lista;] ... [else lista;] fi
# Przykład:
if rm plik1.txt; then echo
"usunalem plik1.txt"; fi
... inne postacie instrukcji warunkowej
if [[ warunek ]] then lista; fi
if [ warunek ]; then lista; fi
# przestarzale
if test warunek; then lista; fi
# przestarzale
# przestarzale polecenia istnieja aby zachować zgodność z powłoką "sh"
# Przykład:
if [[ 1 -lt 2 ]] then echo
tak; fi
if [[ 1 -lt 2 || 2 -lt 1
]] then echo tak; fi
# Przykład 1: i=1 while [[ $i -le 5 ]] do echo ">>>"$i"<<<"; i=$((i+1)); done
# Przykład 2: # "true" to komenda której kod zakończenia = 0 (prawda) # pętla kręci się w nieskończoność ... (kończenie dzialania skryptu: Ctrl-C) i=1 while true do echo ">>>"$i"<<<"; i=$((i+1)); done
until list ;do list ;done
for identifier [in word...] ;do list
;done
# Przykład 1:
for i in 1 2 3; do echo
$i; done
# Przykład 2:
for i in 1 2 3
do echo $i; done
# dwa ostatnie przyklady sa rownowazne !!!
select identifier [in word...] ;do
list ;done
# Przykład:
select x in 1 2 3 4; do
echo $x; done
case word in [[(] pattern [| pattern]
...) list ;;] ... esac
# Przykład:
case 5 in
1 | 2 | 3) echo
qqq;;
4 | 5 | 6) echo
www;;
7 | 8 | 9) echo
eee
esac
(lista)
lista jest wykonywana w procesie potomnym
(przez "ksh")
# Przykład:
pwd; (cd ..; pwd); pwd
# kazdy proces ma swoj wlasny biezacy katalog
# skoro "cd .." jest wykonywane w innym procesie
# to nie ma wpływu na katalog bieżący naszego procesu !!!
{lista; }
lista jest wykonywana w procesie
bieżącym
# Przykład:
pwd; { cd ..; pwd; }; pwd
# ostatni ";" wewnatrz {} musi byc !
# tutaj "cd .." jest wykonywane w naszym procesie
# tak więc katalog bieżący się zmieni !!!
# do czego jeszcze moga sluzyc
{} ?
# do przeadresowywanie
calych grup komend :
echo 1; echo 2 > /dev/null
{ echo 1; echo 2; } > /dev/null
# jaka jest różnica ?
# w listach logicznych
do grupowania komend :
true && { echo 1; echo 2; echo 3; }
false && { echo 1; echo 2; echo 3; }
[[ warunek ]]
W "warunku" można używać operatorów języka C:
&& - and || - or ! - not # Przykłady: if [[ -d kat1 && -f plik.txt ]] then echo "kat1 jest katalogiem" echo "plik.txt jest plikiem zwyklym" fi # "-d kat" <=> kat jest katalogiem # "-f plik" <=> plik jest plikiem if [[ 1 -lt 2 ]] then echo tak; fi if [[ ! ( 1 -lt 2 ) ]] then echo tak; fi if [[ 1 -lt 2 || 2 -lt 1 ]] then echo tak; fi # "-lt" <=> "<" # "-le" <=> "<="
Lista
dostępnych operatorów (z manuala "ksh")
*** substytucje (czyli podstawianie)
-> substytucja komend
$(lista)
# Przyklady
:
echo "biezacy
katalog to $(pwd)"
echo "pliki
TXT: $(ls -l | grep "TXT")"
-> substytucja zmiennych
$zmienna
${zmienna}
# Przyklady
:
echo "katalog
HOME to $HOME"
echo "katalog
HOME to ${HOME}abc"
echo "biezacy
katalog to $PWD"
-> substytucja tyldy
# Przyklady
:
echo ~user
# wyswietla
katalog HOME uzytkownika "user"
# (pobrany
z pliku /etc/passwd)
-> jest jeszcze pare innych substytucji ...
# Przyklady bardziej zaawansowane roznych substytucji
...
# przypisuje zmiennej wynik działania złożonego
potoku:
prawa_do_HOME=$(ls -ld $HOME | awk '{print $1}')
echo $prawa_do_HOME
# możliwe jest także dowolne zagnieżdżanie subst.
komend:
prawa_do_kat=$(ls -ld $(pwd) | awk '{print $1}')
echo $prawa_do_kat
# umieszczenie w "zmiennej" zawartości pliku:
zawartosc=$(cat plik.txt)
# plik.txt powinien zawierac kilka linni tekstu
(niektore zawierajace ABC)
# filtrowanie zawartości (wypisuje tylko linie zawierające ABC):
echo "przefiltrowana zawartosc : $(echo "$zawartosc"
| grep 'ABC')"
# UWAGA: w powyzszym przykladzie cudzyslowy sa wazne
!; sprawdz:
echo $zawartosc
echo "$zawartosc"
*** zmienne powłoki i środowiska
jest wiele standardowych zmiennych
$PATH = lista katalogów,
oddzielonych ":", przeszukiwanych w czasie
uruchamiania programu (gdy nie podaliśmy ścieżki do pliku z programem)
$HOME = katalog HOME
użytkownika
$0, $1, $2, ... =
parametry skryptu
$# = ilosc parametrow
skryptu
$? = kod zakonczenia
ostatnie wykonywanej komendy
$PS1, $PS2, $PS3 =
prompt
Lista dostępnych zmiennych (z manuala "ksh")
nadawanie wartości zmiennym (lub tworzenie
nowych)
wykonuje się przy pomocy polecenia:
zmienna1=wartość1 # zmienna1 jest zmienną powłoki NIE należącą do "środowiska" # Przykłady: x1=123 zmienna=qwe zmienna="qwe" x2="qwe asd zxc" #cudzysłowy są niezbędne gdy tekst zawiera spacje export zmienna2=wartość2 # zmienna2 jest "eksportowana" czyli należy do "środowiska procesu" # Przykład: export x1=123UWAGA:
# Dwa przykłady, pokazujące różnicę między zmiennymi # eksportowanymi i nieeksportowanymi : x=123; ksh -c 'echo "\$x=$x"'; unset x export x=123; ksh -c 'echo "\$x=$x"'; unset x
odczytywanie wartości zmiennych (=substytucje zmiennych):
echo $zmienna echo ${zmienna} echo "$zm1,$zm2" echo "zm1=$zm1, zm2=$zm2" echo "qqq${zmienna}www" # koniecznie trzeba użyć "{}" echo "${zmienna:=tekst}" # opis tego wyrażenia i podobnych znajdziesz tutaj
*** generowanie nazw plików
echo *.txt
# wyswietli wszystkie pliki
# z biezacego katalogu o nazwie zgodnej z *.txt
# UWAGA: nie robi tego polecenie echo
# lecz powloka (inaczej niż pod
dos-em !!!)
echo ../../*.cc
# wyświetl pliki *.cc z katalogu ../..
echo abc[0-9]*.txt
# wyświetli pliki typu "abc1yyyyyy.txt", "abc3xxx.txt"
Inne możliwości
generowania nazw plików (z manuala "ksh")
*** cytowanie
Cytowanie to wyłączanie specjalnego
znaczenia znaków
Do cytowania służą :
"napis"
'napis'
\znak
# Co się dzieje z substytucjami podczas
cytowania ???
#
echo *.txt , biezacy katalog $(pwd)
, HOME=$HOME
echo "*.txt , biezacy katalog $(pwd)
, HOME=$HOME"
# cudzysłowy najsłabiej
cytują;
# w ostatnim przykładzie
wyłączają jednie "generowanie nazw plików"
echo 'biezacy katalog $(pwd) , HOME=$HOME'
# apostrofy cytują silnie;
# wyłączają działanie wszystkich
substytucji
echo "biezacy katalog \$(pwd) , HOME=\$HOME"
echo "biezacy katalog $(pwd) , HOME=\$HOME"
# "\" cytuje tylko 1 znak
# Liczba argumentow (cytowanie spacji):
# program
"pr01.c" wyświetla swoje argumenty;
# spacje
maja specjalne znaczenie = rozdzielanie argumentów komendy
#
pr01 "$HOME 2 3" # 1 argument (bo spacje
sa cytowane)
# jak widać, cudzysłowy działają na spację !
pr01 $HOME 2 3 # 3 argumenty
pr01 '$HOME 2 3' # 1 argument (bez substytucji
zmiennej)
pr01 \$HOME 2 3 # 3 argumenty
(bez substytucji zmiennej)
*** przeadresowywanie
komenda >plik
komenda >>plik
# dopisywanie na koniec
pliku
komenda 2>plik
# przeadresowanie "stderr"
do pliku
komenda >plik 2>&1
komenda 1>plik 2>&1
# przeadresowanie
"stdout" do pliku oraz
# przeadresowanie "stderr" tam gdzie przeadresowano "stdout"
# (cyfry które tutaj występują to deskryptory: stdin-0, stdout-1, stderr-2)
są też inne mozliwosci ...
# Przyklad :
cat <plik1.txt | cat | cat
| cat >plik2.txt
*** wyrażenia arytmetyczne
echo "1+1=$((1+1))"
echo "2*2=$((2*2))"
*** (ważniejsze) komendy wbudowane
. skrypt
# (komenda ".") uruchamianie skryptu w ramach bieżącej powłoki
set
# wyswietla zmienne powloki
set -o
# wyswietla biezace opcje powloki
# wylaczenie opcji przy pomocy "set +o"
# Np: set +o vi
jobs; bg; fg; # sterowanie pracami - juz omowione
cd; pwd; # oczywiste ...
break; # wychodzenie z roznych petli
eval arg...; # wykonuje się substytucje;
następnie
# argumenty są traktowane jak komenda i wykonywane
# (substytucje są wykonywane po raz drugi !)
# Przykłady:
x="echo 123"
y='$x'
eval $y # wykonuje sie echo 123
# jak odczytac $i-ty parametr
powloki ???
i=10
eval echo \${$i} # ok
echo ${$i} # błąd !!!
echo arg...; # wypisuje arg na stdout
exec prog; # pojawia sie i zaczyna wykonywac
nowy kod
# (zastepuje kod powloki !!!)
read zmienna; # wczytuje tekst z terminala
# i zapisuje w zmiennej o podanej nazwie
read zmienna?prompt;
# Przykłady:
read x?"Podaj nazwisko "; echo $x
Lista komend wbudowanych
w powłokę "ksh"
-> przyklad skryptu, ktory czyta swoje "stdin" (linia
po linii)
i przepisuje je na "stdout" oraz
"stderr": (plik "skr01");
można się o tym przekonać dokonując
odpowiednich
przeadresowań stdout i stderr
do pliku /dev/null :
skr01 1>/dev/null skr01 2>/dev/null-> przyklad uzycia powloki "ksh" do czegos w rodzaju
-> skrypt analizuje swoje parametry oraz wypisuje
informacje
czy sa one nazwami plikow: (plik
"skr03")
Zadanie 36
--> basename, dirname
# ze ścieżki do pliku "wyciąga" nazwę pliku (bez sufiksu ".gz"): basename /qqq/www/plik.txt.gz .gz plik.txt # ... to samo co wyżej; # dodatkowo umieszcza nazwę pliku w zmiennej nazwa_pliku=$(basename /qqq/www/plik.txt.gz .gz)--> grep, less, more, env
Warto pamietac ze powloka ksh ma wbudowana konstrukcje
do obliczania wartosci wyrazen arytmetycznych:
echo $((2*2))
4
Polecenie expr pozwala robic podobne rzeczy:
expr 1 + 1
2
expr 2 \* 2 # ??? dlaczego \* a nie * ???
4
Zwroc uwage, ze skladniki wyrazenia musza byc
osobnymi parametrami polecenia !.
Jednak polecnie expr ma wieksze mozliwosci niz $(()):
expr "qqqqwww" : "qq*"; echo $?
4
0
expr "qqqqwww" : "qq*$"; echo $?
0
1
W powyzszym przykladzie sprawdza sie czy string "qqqwww"
pasuje do wyrazenia regularnego "qq*" oraz do
"qq*$"
Polecenie wyswietla ilosc znakow pasujacych do wyrazenia.
Kod wyjscia (dostepny poprzez zmienna "?") jest ustawiany
na 0 gdy string pasuje do wyrazenia, na 1 gdy nie pasuje.
Przykladowo "qq*" oznacza string zaczynajacy sie od "q",
po ktorym nastepuje dowolna ilosc literek "q" (byc moze rowna 0).
Wyrazenie "qq*$" oznacza ciagi literek "q" zawierajace
przynajmniej jedna literke.
Jest to polecenie do wykonywania pewnych czynności na całym drzewie katalogów.
Przebiega się wszystkie pliki i katalogi wychodzące z katalog, i dla
każdego pliku/katalogu
oblicza się wyrażenie_logiczne ...
Składnik "-print" wyrażenia logicznego powoduje wypisanie nazwy bieżącego
pliku/katalogu,
co można wykorzystać następująco:
find /usr/bin \( -name '*.c' -o -name '*.cc' \) -print # wyświetla wszystkie pliki w katalogach wychodzących z /usr/bin # które maja nazwę zgodna ze wzorcem *.c LUB *.cc # -o <=> OR (=LUB), -a <=> AND (=I) # Uwaga: w składnikach pierwszego poziomu wyrażenia logicznego # nie trzeba używać -a (i tak są traktowane jak koniunkcja)Dlaczego powyższy przykład działa jak opisałem ?
inny przykład :
find /usr/bin -type d -exec ls -ld {} \; # dla wszystkich plików typu katalog (-type d) wykonuje się # polecenie ls -ld "katalog"
Dokumentacja w j. ang jest w plikach "awk.txt"
oraz "awk2.txt";
jest takze dostepny opis po polsku "Kilka faktów
o awk".
Program "awk" jest to proste narzędzie do przetwarzania tekstu.
W Unix-ie jest używany do "wyciągania" informacji z wyjścia
różnych poleceń takich jak "ls" i "ps".
Program "awk" czyta tekst ze standardowego wejścia.
Tekst ten jest traktowany jak ciąg rekordów
(którymi standardowo są linie
tekstu).
Rekordy dzielą się na pola
(standardowym separatorem pól
jest spacja).
Dostęp do pól rekordu:
$0 - cały rekord,
$1 - pierwsze pole,
$2 - drugie pole,
..........................
..........................
Innymi słowy rekordy to "linie
tekstu", a pola to "słowa w liniach".
Skrypt programu "awk" zawiera pary:
Wzorzec1 { Czynnosc1 }
Wzorzec2 { Czynnosc2 }
......................................
......................................
gdzie "Wzorzec" jest /wyrażeniem regularnym/
lub wyrażeniem logicznym języka C,
natomiast "Czynność" jest kodem zapisanym w języku podobnym do C.
"Czynność" polega zazwyczaj na wypisaniu pewnych informacji.
Rekordy są przeglądane kolejno.
Jeśli pewien rekord jest zgodny ze "Wzorcem", to jest wykonywana "Czynność". |
Istnieja "Wzorce" specjalne BEGIN i END zgodne z pierwszym i ostatnim rekordem.
Przyklady:
ls -l | awk '{print $1 " " $9}'
# wypisuje tylko prawa i nazwy plikow ("pola"
o nr 1 i 9).
# w tym przykładzie "wzorzec" jest pusty <=> wszystkie
rekordy są z nim zgodne
ls -l | awk '$2>10{print $0}'
# wypisuje tylko te pliki które mają "liczbę
dowiązań" > 10.
ps -o pid,ppid | awk '$2==1234
{print $1}'
# wypisuje PID-y procesów z PPID=1234
awk 'BEGIN {s=0};
/^[0-9]+$/ {s=s+$1};
END {print "suma liczb
calkowitych = " s}'
# dodaje wszystkie linie ktore
# zawieraja tylko i wylacznie liczbe calkowita
awk ' {tablica[$1]=tablica[$1]","$2};
END {for (x in tablica) {print x " " tablica[x]}}'
# jeśli na wejściu dostanie:
1 a
1 b
x q
2 a
1 c
2 b
x w
x e
# to zwróci wynik:
1,a,b,c
2,a,b
x,q,w,e
The $ matches the end of the string.
A \ followed by a single character matches that character (???)
A . matches any character.
A single character with no special meaning matches that character.
A string enclosed in brackets [] matches any single character
in that string.
Ranges of ASCII character codes may be abbreviated as
'a-z0-9'.
A left bracket ] may occur only as the first character
of the string.
A literal - must be placed where it can't be mistaken
as a range indicator.
If the first character is the caret ^ then any character
not in the
string will match.
A regular expression followed by * matches a sequence of
0 or more
matches of the regular expression.
A regular expression followed by + matches a sequence of
1 or more
matches of the regular expression.
A regular expression followed by ? matches a sequence of
0 or 1
matches of the regular expression.
Two adjacent (concatenated) regular expressions match a
match of the first
followed by a match of the second.
Two regular expressions separated by | match either a match
for the
first or a match for the second.
A regular expression enclosed in parentheses matches a
match for the
regular expression.
The order of precedence of operators at the same parenthesis
level is
[] then *+? then concatenation then |.
sygnal2 -kill 1234UWAGA: to wymaga wyrafinowanego użycia "awk"; (przeanalizuj przyklad "awk01")
wymiana_naglowkow naglowek.txt plik1.txt plik2.txt ...Skrypt ten powinien ZAMIENIC naglowki plikow "plik?.txt"
powiadom_mnie jkowalskiwyswietlajac odpwiednie napisy na terminalu
--- polecenie ---Przydatne polecenia: "grep"+wyr.reg., "head"
pol1 pol2 pol3 ...a następnie tworzy pliki "ascii" o nazwach
pol1.txt pol2.txt pol3.txt ...zawierajace tresc manuala BEZ kodow przeznaczonych dla
sed -e 's/tekst1/tekst2/g'Pytanie: jak wprowadzać znaki typu ^A, ^B, ^H (o kodach 1, 2, 8) ?
Uwaga do zadania S19: plik nie powinien być przekazany do skryptu(1) qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq (2) wwwwwwwwwwwwwwwwwwwwwww ..................... .....................