Cislovani je urcite jine nez na cviceni. (1) Vypsat poslednich deset prihlasenych uzivatelu. (2) Vypsat jmeno skupiny s tretim nejvyssim gid (ciselnym ID). (3) Vypsat, kolik uzivatelu pouziva ktery login shell (standardni shell, ktery se uzivateli spusti po zalogovani; sedma polozka v /etc/passwd). (4) Vystup predchoziho reseni obsahuje na zacatku radku mezery. Vymyslete, jak je odstranit. (5) Specialni ulozka pro supermany - mam pismeno, jak zjistim, kolikate je v abecede (bez toho, abych vypisoval ve skriptu celou abecedu)? (Zatim nevyreseno.) (Muzete pouzivat i featurky bashe.) (6) Vypiste jmena vsech uzivatelu na jedne radce. (Diky Martinu Prihodovi za seznam vsech ulozek.) ----------------------------------------------------------------------- ----------------------------------------------------------------------- Reseni: (1) Trivialni: last | cut -d\ -f 1 | head Pozor, za -d jsou dve mezery, jedna patri k zpetnemu lomitku a druha oddeluje dalsi parametr. Citelneji to muzeme zapsat jako: last | cut -d" " -f 1 | head Navic prikaz last samotny umi brat parametr -n, ktery omezuje pocet vypsanych zalogovani: last -n 10 | cut -d" " -f 1 (2) Pozor, musime vypisovat ze souboru /etc/group, nikoliv /etc/passwd (nektere skupiny nemusi byt primarni pro kazdeho uzivatele). Pouzijeme strategii rozdel a panuj - nejdrive zjistime ID skupiny a pak podle tohoto ID zjistime jeji jmeno. cut -d : -f 3 /etc/group | sort -n | tail -n 3 | head -n 1 >gid nam nejdrive vytahne vsechny gid z /etc/group, pak je numericky setridi (tak, ze nejvyssi bude na konci), a nakonec vytahne treti radek od konce. To si ulozime do nejakeho souboru gid. Ted podle gid zjistime jmeno skupiny. Naivni pristup grep `cat gid` /etc/group | cut -d : -f 1 NEFUNGUJE. Nejdrive vypiseme vsechny radky /etc/group, ktere obsahuji hledane cislo skupiny, a pak vytahneme z radku jmeno skupiny. Kdyz ale nami hledane cislo skupiny je treba 27, vypise grep i radky pro gid 127, 3274, nebo skupinu jmenem 'stastnecislo27'. Navic je slusnosti vystup z `` vzdycky zavirat do uvozovek. Nase reseni je tedy: cut -d : -f 3 /etc/group | sort -n | tail -n 3 | head -n 1 >/tmp/gid grep `cat /tmp/gid` /etc/group | cut -d : -f 1 rm /tmp/gid (Docasne soubory je slusnosti delat v /tmp a smazat je po sobe; na pristim cviceni si o docasnych souborech povime vice, a mrkneme se na to, jak priklad vyresit pomoci promenne.) Muzeme ale pomerne jednoduse zajistit, aby grep vytahl pouze cisla, ktera jsou sama o sobe obsahem nejake polozky v /etc/group: grep ":`cat gid`:" /etc/group | cut -d : -f 1 Protoze sloupecky jsou oddeleny znakem ':', takto vypiseme pouze radky, ve kterych mame polozku, ktera obsahuje _prave_ nase gid. Tento pristup bude spolehlive fungovat u seznamu skupin, u jinych souboru vsak nemusi, treba v souboru /etc/passwd bychom nemohli rozlisit napr. uid a gid uzivatele. V takovem pripade bychom si pomoci prikazu cut a paste museli soubor predelat napr. pouze do formatu jmeno:id (za cviceni si vymyslete, jak - je to jednoducha posloupnost tri prikazu) a pak pomoci grepu uz muzeme vzdy jednoznacne vybrat pouze radek, ktery nas zajima: grep ":`cat gid`\$" nassoubor | cut -d : -f 1 Pozn.: znak $ znaci v regularnim vyrazu konec radku, my jsme pred nej museli napsat zpetne lomitko, protoze jde zaroven o specialni znak shellu - takto grep uvidi regularni vyraz, ktery dostal jako parametr, pro gid=12345 jako: :12345$ (3) Jednoduche: cut -d : -f 7 | sort | uniq -c Nejdrive ze vsech radek vyberu pouze login shelly, pak pomoci sortu dam jednotlive shelly "k sobe" a pak pomoci uniq -c vlastne spocitam, kolikrat se mi ktery login shell vyskytl. A to je presne ta hodnota, ktera me zajimala. (4a) Vsimneme si, co dela tento prikaz: ... | tr -s " " Pokud jim prozeneme (3), zmensi se nam pocet mezer na jednu - ted jen jak se zbavit te jedne mezery... Muzeme pouzit trik - predstavme si, ze mame vstup jako nekolik sloupecku oddelenych mezerou, pak ale jedna mezera na zacatku radku neni nic jineho nez vytvoreni prazdneho sloupecku navic - a neni nic jednodussiho, nez se ho pomoci cutu zbavit: ... | tr -s " " | cut -d" " -f 2- Toto reseni ma vsak jedno ALE - sice zrovna u login shellu to nevadi, pokud byste vsak tuto operaci delali nad jinymi daty, prikaz tr by splacnul nejen uvodni mezery, ale i uvodni mezery ve zbytku radku, treba z " 1234 foo bar" by neudelal " 1234 foo bar" ale " 1234 foo bar" Tento problem uz neobejdeme prilis snadno - napada me jeden zpusob, jak se s tim vyporadat, je vsak pomerne slozity a hlavne prasacky. ;-) (4b) Pomerne jednoduse vsak problem muzeme vyresit, vydame-li se uplne jinudy a pouzijeme substituci regularnimi vyrazy v sedu: ... | sed 's/^ *//' Na kazdy radek se aplikuje sedovy prikaz s/^ *// ktery zasubstituuje podretezec, ktery se matchne regexpem (regularnim vyrazem) ^ * za prazdny podretezec (tedy jej vymaze). V regularnim vyrazu ^ vyjadruje zacatek radku a hvezdicka libovolny pocet opakovani predchoziho znaku. Regexpy se matchuji hladove, tedy se najde maximalni mozny vyskyt. Prikaz tudiz vymaze vsechny mezery na zacatku radku, coz je presne to, co jsme chteli. (5) Zatim nikdo (krome me ;) nevyresil. (6) Vypiste jmena vsech uzivatelu na jedne radce. Trivialni ulozka na tr: cut -d : -f 1 | tr '\n' ' '