V shellu mají jisté znaky speciální význam. Pro rychlou orientaci v těchto znacích je připravena tabulka.
Speciální znaky | Význam |
---|---|
| | roura (pipe) - řazení příkazů do kolony |
& | spuštění na pozadí |
; | ukončení příkazu |
( ) | spuštění v kopii shellu |
> | presměrováná standardniho výstupu |
< | presměrování standardniho vstupu |
&& | spuštění při nulovém návratovem kódu |
|| | spuštění při nenulovém návratovem kódu |
$ | umozňuje přístup k promenným |
* ? [ ] | znaky pro expanzi jmen |
\ | potlačuje význam následujícího speciálního znaku |
' ' | potlačuje význam speciálních znaků |
" " | potlačuje význam speciálních znaků až na \, $ a ` ` |
` ` | vrátí standardní výstup příkazu |
Některé speciální znaky si ukážeme na příkladech
who | wc -l | vypíše počet přihlášených uživatelů |
sh -c 'sleep 5;date'& echo Date: | vypíše Date: a po 5 sekundách datum a cas |
cd;pwd;(cd /etc;pwd;);pwd | vypíše název domovského adresáře, pak /etc a pak zase domovský adresář |
tr ay ya <in | tee out | v souboru in prohodí znaky a a y a výsledek vypíše na obrazovku a do souboru out |
read DIR; test -d $DIR && echo $DIR je adresar | zjistí, zda $DIR je adresář |
tar cvf - $*$.[ch] | compress >etc.tar.Z | zabalí a zkompresuje soubory v aktuálním adresáři končící na .c a .h |
cat a b c > d | spojí soubory a, b, c do souboru d |
du -s $HOME | ukáže, kolik místa zabírají naše data |
find /etc -name '*' -exec grep -l xdobiasl {} \; | vypíše soubory v adresáři /etc, které obsahuji dané slovo (vypíše asi /etc/passwd) |
more `which startx` | vypíše soubor, kterým se spouští X Window |
for i in *; do echo "Balim $i"; compress $i; done | v aktualnim adresáři zkompresuje každý soubor zvlášť |
expr `cat /etc/passwd | sort -t : -n -k 3 | tail -1 | awk '{ FS=":"; print $3 }` + 1 | vypíše UID o jednicku vyšší, než je v systému nejvyšší |
Každý proces v UNIXu má k dispozici parametrem jádra stanovený počet komunikačních kanálů (50-60) pro manipulaci se soubory. Otevření souboru znamená alokaci kanálu, obsazení další položky v tabulce. Nově vytvořený proces přebírá ("dědí") po svém otci mimo jiné také tuto tabulku otevřených kanálů. Tabulka kanálů obsahuje 3 záznamy i v případě, že otec žádný ze souborů explicitně neotevřel. Jsou to obsazená místa kanálů č. 0, 1 a 2.
Kanál č. 0 je označován jako standardní vstup a je otevřen pro čtení z klávesnice terminálu, kanál č. 1 je standardní výstup, je otevřen pro zápis na obrazovku terminálu a stejně tak je pro zápis na obrazovku terminálu otevřen kanál č. 2, označovaný jako standardní chybový výstup. V rámci shellu je možné manipulovat se standardním vstupem i výstupem za pomoci speciálních znaků. Příkaz
$ ls -l > seznam
nevypisuje atributy souborů pracovního adresáře na obrazovku terminálu, výpis je ukládán do souboru seznam
. Je toho dosaženo zápisem speciálního znaku >
, který shell rozpozná a interpretuje jako přepnutí standardního výstupu procesu ls
do souboru seznam
. Soubor seznam
je nově vytvořen, pokud již existoval, jeho předchozí obsah je ztracen. Standardní výstup lze přesměrovat i způsobem, kdy původní obsah souboru bude zachován, přepnutý obsah standardního výstupu k němu bude pouze připojen. Toho se dosáhne zápisem >>
:
$ ls -l >> seznam
Znakem <
přepínáme standardní vstup.
$ rm -i > soubor < potvrzeni
čte program rm
ze souboru potvrzeni
namísto z klávesnice terminálu.
Standardní chybový výstup se přesměruje do souboru chyby
takto
$ cc prog.c 2>chyby
Lze také obecně spojovat tok dat určitého kanálu s kanálem jiným. Např. standardní chybový výstup lze napojit na kanál č. 1 zápisem
$ time ls > mereni 2>&1
|
vytváří shell rouru. Tímto mechanizmem, který jádro realizuje na požádání shellu, lze propojovat sekvenčně současně několik procesů. Příkazový řádek pak nazýváme kolona.
Následující příklad na standardní výstup vypisuje počet souborů v daném adresáři:
$ ls | wc -l
Užitečný je program tee
. Jeho název je odvozen z vodoinstalační terminologie. Jde o odbočku z roury. Odbočka svede standardní vstup do souboru daného parametrem a současně jej předává na standardní výstup:
$ who | tee kdo | grep jan | wc -l
* |
libovolná posloupnost znaků (i nulové délky), nezastupuje řetězec znaků začínající tečkou |
? |
právě jeden libovolný znak |
[znaky] |
právě jeden znak z množiny znaků uvedených v těchto závorkách, při specifikaci lze použít následující dva speciální znaky: |
- |
používa se pro označení intervalů znaků z množiny ASCII (např. a-z, 0-9), |
! |
negace výčtu znaků |
Metaznaky můžeme použít pro specifikaci jména souboru v libovolném příkazu. Substituci konkrétních jmen souborů provádí shell, ne vlastní program. Napr. po zadání příkazu
$ ls -l /bin/l*
shell interpretuje metaznaky, a spustí program ls s příkazovou řádkou:
$ ls -l /bin/ld /bin/line /bin/ln /bin/login /bin/logname /bin/ls /bin/ltf
;
oddělujeme příkazy:
$ pwd; ls -l
Sekvence příkazů můžeme sdružovat do skupin. Závorky {
a }
vymezují skupinu příkazů, je na ni ale implicitně startován nový proces sh.
$ { cat /usr/jan/seznam; ls;} | grep *.c
\ |
snižuje význam znaku za ním následující na úroveň ostatních znaků, shell neuvažuje jeho speciální význam. Pokud se obrácené lomítko zapíše na konec řádky, potlačí se obvyklý význam znaku konce řádky - vznikne pokračovací řádek. |
'řetězec' |
apostrofy označují řetězec, kde znaky zvláštního významu jsou považovány za běžné znaky, |
"řetězec" |
uvozovky označují řetězec, kde znaky zvláštního významu jsou považovány za běžné znaky, kromě znaku dolar ($) a opacné apostrofy (` `), |
$proměnná |
odkaz na obsah příslušné promenne, |
`příkaz` |
obrácené apostrofy označují, že se na jejich místě má doplnit standardní výstup programu uvedeného v apostrofech. |
$
, kterou mu bylo sděleno, že interpretace byla ukončena. Bez toho, abychom čekali na ukončení příkazu a bylo nám umožněno zadávat další příkazy, je možné spustit příkaz na pozadí (background). Dosáhne se toho speciálním znakem &
, který bude uveden jako poslední na příkazovém řádku.
$ ls -l > seznam &
231
$
Na pokyn $
můžeme ihned zadávat další příkaz. Shell vypsal na standardní výstup identifikační číslo procesu (PID) spuštěného na pozadí, zde 231
. Slouží uživateli k manipulaci s procesem programu na pozadí. Pokud by se např. proces spuštěný na pozadí zacyklil může mu uživatel zaslat signál, na který proces reaguje ukončením činnosti. PID má každý proces v době svého vzniku přiděleno, u procesů běžících na popředí se implicitně nezobrazuje.
Jiný způsob jak dostat proces na pozadí je udělat to, když už program běží. Nejprve spusťte nějaký program. Když běží, stiskněte control+z
. To ten proces pozastaví. Okamžitě zastaví jeho běh, ale může být kdykoliv znovu rozběhnut. Jakmile je proces pozastaven, vrátí se vám na monitor prompt. Pak můžete rozběhnout pozastavený proces na pozadí tak, že napíšete:
$ bg
Pokud chcete komunikovat s upozaděným procesem, můžete jej přenést zpět do popředí. Máte-li upozaděný pouze jediný proces, můžete jej přenést do popředí tak, že napíšete:
$ fg
Je možné mít vícero upozaděných procesů najednou. Pokud se to stane, budete potřebovat vědět jak dostat do popředí jeden konkrétní proces. Pouhým zapsáním fg
půjde dopředu proces, který byl upozaděn jako poslední. Ale co když máte na pozadí celou řadu procesů? Naštěstí bash obsahuje příkaz, umožňující všechny procesy vypsat. Ten příkaz se jmenuje jobs
a poskytuje takovýto výstup:
$ jobs
[1] Stopped vim
[2]- Stopped amp
[3]+ Stopped man ps
To vám ukazuje seznam všech procesů, které jsou na pozadí. Jak vidíte, všechy jsou pozastavené (stopped). Číslo na začátku je identifikátorem upozaděného procesu. Číslo za nímž je plus označuje proces, který by se dostal do popředí, kdybyste napsali pouze fg
.
Pokud chcete dostat do popředí vim
, musíte napsat:
$ fg 1
ps
:
$ ps
PID TTY TIME COMMAND
31 01 0:03 sh
44 01 0:00 ls
45 01 0:00 ps
$
Můžete získat úplný seznam procesů, běžících na vašem systému, když použijete správnou kombinaci voleb. To pravděpodobně vyústí v předlouhý seznam procesů:
$ ps -ax
PID TTY STAT TIME COMMAND
1 ? S 0:03 init [3]
2 ? SW 0:13 [kflushd]
3 ? SW 0:14 [kupdate]
4 ? SW 0:00 [kpiod]
5 ? SW 0:17 [kswapd]
11 ? S 0:00 /sbin/kerneld
30 ? SW 0:01 [cardmgr]
50 ? S 0:00 /sbin/rpc.portmap
54 ? S 0:00 /usr/sbin/syslogd
57 ? S 0:00 /usr/sbin/klogd -c 3
59 ? S 0:00 /usr/sbin/inetd
61 ? S 0:04 /usr/local/sbin/sshd
63 ? S 0:00 /usr/sbin/rpc.mountd
65 ? S 0:00 /usr/sbin/rpc.nfsd
67 ? S 0:00 /usr/sbin/crond -l10
69 ? S 0:00 /usr/sbin/atd -b 15 -l 1
77 ? S 0:00 /usr/sbin/apmd
79 ? S 0:01 gpm -m /dev/mouse -t ps2
94 ? S 0:00 /usr/sbin/automount /auto file /etc/auto.misc
106 tty1 S 0:08 -bash
108 tty3 SW 0:00 [agetty]
109 tty4 SW 0:00 [agetty]
110 tty5 SW 0:00 [agetty]
111 tty6 SW 0:00 [agetty]
[výstup zkrácen]
kill
(zabít) a k ovládání procesů může být použit několika způsoby. Nejobvyklejším použitím příkazu kill
je zabití procesu.
Abyste mohli proces zabít, budete potřebovat znát buď jeho PID, nebo jeho jméno. Pro získání PID použijte příkaz ps
, který jsme probrali v předchozí sekci. Například, abyste zabili proces s číslem PID 4747, napište tohle:
$ kill 4747
Upozorňuji, že musíte být vlastníkem procesu, abyste ho mohli zabít. To je bezpečnostní opatření. Kdybyste měli právo zabíjet procesy spuštěné ostatními uživateli, asi by to způsobilo pár zmatků. Nicméně root může zabít jakýkoliv proces v systému.
Ještě máme další variantu příkazu kill
, nazvanou killall
. Tento program dělá přesně to, co říká (zab všechny): Zabíjí všechny běžící procesy zadaného jména. Kdybyste chtěli zabít všechny běžící procesy vim
, napsali byste následující příkaz:
$ killall vim
Někdy pouhý kill
na svou práci nestačí. Některé procesy pomocí kill
prostě nezemřou. Na takové budete potřebovat účinnější formu. Pokud třeba takové urputné PID 4747 neodpovědělo na váš vražedný požadavek, měli byste udělat následující:
$ kill -9 4747
To téměř jistě přivede proces 4747 k smrti. Totéž můžete udělat pomocí killall
. Co se přihodilo je to, že byl procesu zaslán jiný signál. Obyčejný kill
posílá procesům signál SIGTERM (terminate - ukončit). kill -9
posílá procesům signál SIGKILL (kill - zabít). K dispozici máte celou řadu různých signálů. Jejich seznam můžete získat napsáním:
$ kill -l
1) SIGHUP 2) SIGINT 3) SIGQUIT 4) SIGILL
5) SIGTRAP 6) SIGABRT 7) SIGBUS 8) SIGFPE
9) SIGKILL 10) SIGUSR1 11) SIGSEGV 12) SIGUSR2
13) SIGPIPE 14) SIGALRM 15) SIGTERM 17) SIGCHLD
18) SIGCONT 19) SIGSTOP 20) SIGTSTP 21) SIGTTIN
22) SIGTTOU 23) SIGURG 24) SIGXCPU 25) SIGXFSZ
26) SIGVTALRM 27) SIGPROF 28) SIGWINCH 29) SIGIO
30) SIGPWR
top
a spouští se takto:
$ top