Prvé cvičenie
Otvorte si ľubovoľný shell
- Prihlásením cez SSH k vhodnému serveru (s.ics.upjs.sk)
- V Linuxe spustením terminálu.
- Na Windowse nainštalovaním prostredia CygWin
Vypíšte Hello World
echo Hello World
Vypíše dva stringy: Hello
a World
.
Alternatívne:
echo "Hello World"
V tomto prípade je Hello World
uvedený ako double quoted string. Shell rozoznáva viacero druhov reťazcov, o nich potom.
Kalkulačka
Vyskúšajte vlastnosti kalkulačky, zrátajte (2 + 3) * 10.
Prvý pokus
(2 + 3) * 10
povedie k chybe:
Syntax error near unexpected token *10
Shell totiž nie je vyhodnocovač aritmetických výrazov (na rozdiel od Powershellu, či pythonovského REPL).
Riešenie:
echo $(((2+3)*10))
$((..)) je prostredie pre vyhodnocovanie matematických výrazov.
V starých bash
och sa používa
echo $[(2+3)*10)]
Toto je deprecated, odporúča sa používať hore-uvedenú notáciu.
Zistite, koľko je 5 deleno 2 [cez shell]
Polosprávne riešenie
echo $((5 / 2))
Výsledkom je:
2
Aritmetické prostredie podporuje len celočíselnú aritmetiku.
Ak chcete reálnu aritmetiku, použite napr. nástroj bc
, univerzálnu kalkulačku s ľubovoľnou presnosťou.
Zistiť aktuálnu verziu shellu
Na Bashi funguje
echo $SHELL
Výpisy adresárov
Zistite, v ktorom adresári sa práve nachádzate.
Zistiť to môžeme pohľadom na výzvu (prompt).
Zistite, v ktorom adresári sa práve nachádzate pomocou pwd
.
pwd
Zobrazte súbory a adresáre v aktuálnom podadresári pomocou ls
.
ls
Zobrazte len názvy súborov či adresárov v aktuálnom adresári.
ls –1
Parametre majú dlhú formu (cez –) a krátku formu (cez -). Nefunguje svojvoľné skracovanie parametrov ako v PowerShelli.
Vypíšte obsah vlastného domovského adresára [variant 1]
cd
ls
cd
bez parametrov presúva do domovského adresára.ls
vypíše obsah aktuálneho adresára
Vypíšte obsah vlastného domovského adresára — viacero príkazov na riadku
Na riadku možno uviesť viacero príkazov oddelených bodkočiarkou:
cd;ls
Expanzia vlnky
Vypíšte cestu k domovskému adresáru
echo ~
Výsledkom je (napr.)
/home/novotnyr
Pred vykonaním príkazu prebehne v shelli expanzia slov (word expansion), kde sa počas viacerých fáz vykoná nahrádzanie špeciálnych _token_ov. Fázy teraz nebudeme rozoberať, zaujíma nás len prvá: expanzia vlnky.
Ešte pred vykonaním príkazu sa vlnka ~
nahradí slovom, ktoré obsahuje cestu k domovskému adresáru. Príkaz echo ~
teda expanduje napr. na echo /home/novotnyr
a až následne sa vykoná.
Skutočná cesta sa berie z premennej $HOME
, ale o tom neskôr.
Vypíšte cestu k domovskému adresáru roota
echo ~root
Expanzia vlnky má špeciálnu vlastnosť: ak uvedieme za ňou login používateľa, expanduje sa na cestu k jeho domovskému adresáru:
/root
Ale zase
echo ~novotnyr
vedie k
/home/novotnyr
Poznámka
Špecifikácia k expanzii vlnky je na http://pubs.opengroup.org/onlinepubs/009695399/utilities/xcu_chap02.html#tag_02_06_01
Späť k adresárom
Vypíšte obsah vlastného domovského adresára — ls
s parametrom
Z ľubovoľného adresára:
ls ~
Parameter ls
uvádza adresár, ktorého obsah sa má vylistovať. V tomto prípade
sa príkaz expanduje na
ls /home/novotnyr
a vypíše sa výsledok (napr.)
data public_html
Vypíšte všetky súbory a adresáre v /home
ls /home
Filozofia je rovnaká ako v predošlom príklade:
apache john25 novotnyr
Vypíšte všetky súbory a adresáre v /home
pod seba
ls -1 /home
Vypíše jeden súbor na riadok:
apache
john25
novotnyr
Vytvorte adresár textfiles
v domovskom adresári
cd
mkdir textfiles
cd textfiles
Vytvorte tri prázdne súbory file1.txt
…file3.txt
a súbor data.dat
.
touch file1.txt file2.txt file3.txt data.dat
Vypíšte zoznam všetkých súborov [repríza, expanzia cesty]
echo *
Čo sa presne stane?
Spomínali sme, že pred vykonaním príkazu prebehne v shelli word expansion. O niekoľko fáz po expanzii vlnky prebieha expanzia cesty (pathname expansion), zvané tiež globbing
Každý globbovateľný výraz expanduje na zoznam názvov súborov, ktoré spĺňajú jeho definíciu. Napr. *
znamená „ľubovoľný reťazec” a v adresári z predošlého príkladu expanduje na
file1.txt file2.txt file3.txt data.dat
Príkaz
echo *
sa teda expanduje na
echo file1.txt file2.txt file3.txt data.dat
Vypíšte zoznam všetkých .txt
súborov
echo *.txt
to expanduje na všetky názvy súborov, ktoré začínajú ľubovoľným reťazcom a končia na .txt
, čiže všetky texťáky.
Globbing
V globbingu sa používa obmedzená sada regulárnych výrazov podobná C:
* hviezdička (nematchuje skryté súbory!)
* otáznik
* zoznam znakov v hranatých zátvorkách
* zobákom sa neguje
Globbing je záležitosť shellu a nie operačného systému! Rozličné shelly môžu ponúkať ďalšie pokročilé možnosti pre globbing.
Historické okienko: v 70tych rokoch globbing nefungoval, riešil sa cez /etc/glob
, ktorý hľadal súbory v /bin
, neskôr v PATH
, teraz sa hľadá v aktuálnom adresári. Popis viď http://cm.bell-labs.com/cm/cs/who/dmr/man71.pdf
Vypíšte zoznam všetkých .txt
súborov [verzia 2, cez ls
, podivná]
ls *.txt
Toto bude fungovať, ale zo zlých dôvodov.
V skutočnosti tento príkaz expanduje na
ls file1.txt file2.txt file3.txt
ls
teda vypíše obsah súboru file1.txt
, file2.txt
atď, čo zhodou okolností urobí presne to, čo chceme.
Vypíšte všetky súbory a adresáre v /etc
, ktoré sa začínajú na „p“.
echo /etc/*p
Keďže poznáme zásady globbingu, máme, čo sme chceli.
Zlý nápad
ls /etc/p*
Opäť prebehne expanzia a až následne spustenie ls
. Výraz /etc/p*
expanduje na zoznam súborov (u vás na iný):
/etc/pam.conf /etc/pam.d /etc/pango /etc/papersize /etc/passwd /etc/passwd- /etc/perl /etc/php5 /etc/phpmyadmin /etc/ppp /etc/profile /etc/profile.d /etc/protocols /etc/pulse /etc/python /etc/python2.6
Príkaz teda bude?
ls /etc/pam.conf /etc/pam.d /etc/pango /etc/papersize /etc/passwd /etc/passwd- /etc/perl /etc/php5 /etc/phpmyadmin /etc/ppp /etc/profile /etc/profile.d /etc/protocols /etc/pulse /etc/python /etc/python2.6
ls
postupne vypíše súbor pam.conf
, ale následne vypíše obsah adresára /etc/pam.d
, čo nie je to, čo chceme, následne vypíše /etc/pango
, atď.
Zlý nápad cez grep
ls | grep p*
Začne grepovať obsahy súborov.
Verzia cez find
find –name "p*"
Funguje, ale začne hľadať aj v podadresároch rekurzívne.
Verzia cez find
(korektná, nerekurzívna)
find -name 'p*' -maxdepth 1
Verzia cez ls
ls –d /etc/p*
Dokumentácia tvrdí, že parameter –d
pre argument typu adresár nevypíše jeho obsah, ale meno. To vieme s výhodou použiť a zabrániť divokému listingu pre položky expandované v globbingu.
Vypíšte všetky súbory a adresáre v /etc
, ktoré sa začínajú na „p“ pod seba
printf "%s\n" *
printf
má známu syntax z C. Pozor ale: nepoužívajú sa zátvorky oddeľujúce argumenty a ani čiarky! Používame shellovú filozofiu! printf
má minimálne parametre: formátovací reťazec a dáta.
V tomto prípade sa expanduje na
printf "%s\n" file1.txt file2.txt file3.txt
Hoci máme len jeden formátovací príkaz %s
, ten sa opakovane použije na všetky parametre, kým to ide. \n
je klasický koniec riadka.
Spočítajte počet súborov z predošlej úlohy
Použijeme wc
, počítadlo slov, riadkov…
echo /etc/*p | wc -w
Parameter -w
spočíta počet slov na vstupe.
Alternatívne
ls –d /etc/p* | wc -l
Parameter -l
spočíta počet riadkov na vstupe.
Vypíšte len adresáre v domovskom adresári
ls –l | grep "^d"
Alternatívne
find . –type d –maxdepth 1
Alternatívne
ls –d */
Výraz */
expanduje na zoznam adresárov ukončených lomkou
public_html/ textfiles/
Celý ls -d */
expanduje na
ls –d public_html/ textfiles/
Parameter -d
zabráni tomu, aby sa ls
postupne vnáral do adresárov, ale vypíše len ich mená.
Zlý pokus
Pokus s –d
nevedie k ničomu. Dokumentácia tvrdí, že parameter –d
pre argument typu adresár nevypíše jeho obsah, ale meno.
ls -d
Zistite, koľko súborov sa nachádza v domovskom adresári a jeho podadresároch.
find . –type f | wc -l
Vypíšte súbory a adresáre v domovskom adresári zotriedené podľa mena
ls | sort
Tento príkaz robí to isté, čo prostý ls
, pretože súbory na výstupe sú už štandardne zotriedené podľa mena.
Vypíšte súbory zotriedené podľa veľkosti
ls –la | sort –k5n
Parametre:
* -l
vypíše kompletný tabuľkový zoznam
* -a
vypíše aj skryté súbory
Parametre pre sort
:
* -k5n
utriedi podľa piateho stĺpca, ktorý bude chápať ako číslo (-n
). Stĺpce sú defaultne
oddelené bielymi miestami.
Alternatívne cez ls –S
`ls -Sa1`
-S
sortí podľa veľkosti,-a
berie aj skryté súbory,-1
vypíše pod seba len názvy
Poznámka
Sortiť sa dá aj cez
-X
podľa prípony-S
podľa veľkosti-t
podľa času-v
podľa verzie
Vypíšte súbory a adresáre zotriedené podľa veľkosti zostupne
ls –la | sort –k2,2n -r
Nájdite najväčší súbor v domovskom adresári (nevnárajte sa do podadresárov)
ls –la | sort –k5,5n –R | tail –n 1
Alebo naopak
ls –la | sort –k5,5n | head –n 1
Osekať zbytočné dáta môžeme awk
om.
Alternatívne cez find
find . –maxdepth 1 –type f –printf "%f\t%s\n" |sort –k2n | tail –n1 |cut –f1
Alternatívne cez find
a ls
find / -type f -exec ls -s {} \; | sort -n | tail -1
Alternatívne cez du
, ls
, head
a subshell
du -k $(ls -Sa1 | head -n1)
- Parameter
-k
vypisuje 1024bajtové bloky miesto štandardných 512bajtových. - Parameter
-S
je GNU parameter pre triedenie podľa veľkosti - Parameter
-a
vráti aj skryté súbory. head -n1
vráti prvý riadok
Vypíšte plné cesty k všetkým súborom a adresárom v aktuálnom adresári
ls -d1 $PWD/*
Grepovanie
Vypíšte mená používateľov v systéme
Úvaha: vypíšeme používateľov podľa adresárov z /home
. Nie každý používateľ však musí mať domovský adresár, a už vôbec nie v /home
(príkladom je root
v /root
).
Prvý nástrel:
cat /etc/passwd | cut -d":" -f1
Toto je ale zbytočné použitie cat
. Postačí presmerovanie súboru na štandardný vstup programu cat
cut -d":" -f1 < /etc/passwd
Vypíšte mená používateľov, ktorí nemajú domovský adresár v /home
Môžeme zobrať šiestu položku z /etc/passwd
a overiť, že nezačína na /home
:
cut -d':' -f6 /etc/passwd | grep -v ^/home
Parameter -v
znamená negáciu pre grep
. Zobák znamená “od začiatku riadku”.
Ak chceme aj mená používateľov, vyberme prvú a šiestu položku. Pozor, cut
nedokáže vrátiť najprv šiestu a potom prvú položku, preto musíme upraviť výraz: hľadáme výraz začínajúci dvojbodkou a /home
:
cut -d':' -f16 /etc/passwd | grep -v :/home
Vypíšte skupiny, do ktorých patrí používateľ X
cat /etc/group | grep novotnyr | grep –v ^novotnyr | cut –d : -f1
Toto je nezmyselné použitie cat
u. Použime buď presmerovanie:
grep novotnyr < /etc/group | grep –v ^novotnyr | cut –d : -f1
alebo využime vlastnosť grep
u, ktorý môže zobrať aj názov súboru ako parameter
grep novotnyr /etc/group | grep –v ^novotnyr | cut –d : -f1
Alternatívne
grep [,:]novotnyr /etc/group | cut –d : -f1
Zaspievajte si so shellom “Šedzi mucha na scene”
Vytvorme mucha.txt
Sedzi mucha na scene
na scene
na scene
sedzi mucha na scene
sedzi a spi
sedzi a buvinka
potvora malinka
sedzi mucha na scene
sedzi a spi
Vyskúšajme
tr aeiou a < mucha.txt
tr
nahrádza jeden znak iným znakom. Berie dva zoznamy znakov a ity znak z prvého zoznamu nahradí itym znakom z druhého zoznamu.
Zobrazte rebríček najpopulárnejšich shellov v systéme
cut -d':' -f7 /etc/passwd | sort | uniq -c | sort -rn
Zobrazte najpopulárnejší shell v systéme
cut -d':' -f7 /etc/passwd | sort | uniq -c | sort -rn | tr -s ' ' | cut -d' ' -f3
Vygenerujte heslo pre používateľa
tr -dc [:alnum:] < /dev/urandom | head -c 10
Vysvetlenie viď: http://ics.upjs.sk/~novotnyr/blog/75/generovanie-hesiel-pre-loginy-v-shelli
Vypíšte 10 krát “Budem si robiť domáce úlohy”
seq 10 | sed 's/.*/Budem si robit DU/'
Vypíšme 10 čísiel na štandardný vstup a každé z nich nahraďme sed
om za konštantný text.
Vypíšte 10 krát “Budem si robiť domáce úlohy” [shell]
#!/bin/bash
for I in 1 2 3 4 5 6 7 8 9 10
do
echo Budem si robit domace ulohy
done
for
cyklus je v skutočnosti foreach
. Prechádza každým slovom za klauzulou in
a vykoná pre ňu iteráciu. (Slovo je reťazec, čísla sa v shelli špeciálne nerozlišujú).
Ak sa nechceme upísať k smrti, môžeme využiť $(...)
: príkaz v tomto prostredí sa spustí v podshelli a jeho výstup sa použije ako výsledok expanzie:
for I in $(seq 10)
spustí príkaz seq
a jeho výstup (slová 1, 2, … 10) sa použije v expanzii:
for I in 1 2 3 4 5 6 7 8 9 10
Celý skript
#!/bin/bash
for I in $(seq 100)
do
echo Budem si robit domace ulohy
done
Skript začína tzv. “shebang” riadkom (od hash bang, teda mreža-výkričník) s cestou k programu, ktorý spustí náš skript — u nás je ním shell.
Vytvorte skript pre generovanie hesla
#!/bin/bash
POCET_ZNAKOV=$1
tr -dc [:alnum:] < /dev/urandom | head -c $POCET_ZNAKOV
printf "\n"
Využime zároveň premennú pre dĺžku. Zásady:
- pri deklarovaní premennej nesmieme použiť dolár
- dolár chápme ako “čítaj obsah z premennej”
- pri priradzovaní hodnoty nesmú byť okolo “rovná sa” medzery
- shell by chápal
POCET_ZNAKOV = 10
ako “zavolaj príkazPOCET_ZNAKOV
a daj mu dva parametre: rovná sa a 10″
- shell by chápal
Premenná $1
obsahuje prvý parameter z príkazového riadka. Skript potom môžeme volať cez
./generuj_heslo 15
Dokonca aj jeho výstup môžeme využiť v podshelli:
echo novotnyr:$(./generuj_heslo 15)