m, zatrachennym na lyuboj ukazannyj proekt. Za- tem mozhno sgenerirovat' statistiku, kotoraya pokazyvaet, kogda i skol'- ko vremeni vy rabotali nad kazhdym proektom. Poslednee sredstvo, otnosyashcheesya ko vremeni - eto komandnyj fajl today. |to utilita, kotoraya izmenyaet vid vyhodnyh dannyh komandy UNIX cal. Ona pechataet obychnyj kalendar', tol'ko tekushchaya data vyvoditsya v inversnom vide. |to ochen' naglyadno. Vy mozhete razvit' etot instrument dlya togo, chtoby otmechat' prazdniki ili drugie osobye dni. ---------------------------------------------------- IMYA: at ---------------------------------------------------- at - vypolnit' komandu ili fajl v ukazannoe vremya NAZNACHENIE Perevodit lyubuyu komandnuyu stroku v fonovyj rezhim i vypolnyaet ee v zadannoe vremya. FORMAT VYZOVA at hr:min cmd [;cmd ...] PRIMER VYZOVA at 12:00 echo "time for lunch!" V dvenadcat' chasov dnya vyvodit soobshchenie na ekran terminala. TEKST PROGRAMMY at 1 : 2 # @(#) tree v1.0 Execute command line at specific time Author: Russ Sage 2a Vypolnit' komandnuyu stroku v ukazannoe vremya 4 if [ $# -lt 2 ] 5 then echo "at: wrong arg count" >&2 6 echo "usage: at hr:min cmd [;cmd ...]" >&2 7 exit 1 8 fi 10 ITS=$1; shift 12 while : 13 do 14 TIME=`date | cut -c12-16` 16 if [ "$ITS" = "$TIME" ] 17 then eval $@ 18 exit 0 19 else sleep 35 20 fi 21 done & PEREMENNYE SREDY VYPOLNENIYA ITS Vremya, v kotoroe sleduet vypolnit' ukazannye komandy TIME Tekushchee vremya v sisteme OPISANIE ZACHEM NAM NUZHEN at? Na protyazhenii rabochego dnya my vypolnyaem mnogo nebol'shih rabot, kotorye nuzhno delat' cherez razlichnye intervaly vremeni. Nekotorye veshchi prosto dolzhny byt' sdelany odin raz v lyuboe vremya, togda kak drugie dolzhny delat'sya v opredelennoe vremya kazhdyj den'. Naprimer, vam mozhet ponadobit'sya zapuskat' proceduru kopirovaniya fajlov kazhduyu noch', vho- dit' v druguyu sistemu raz v den' i proveryat' pochtu ili soobshcheniya pol'- zovatelej seti po zadannoj teme raz v neskol'ko dnej. Komandnyj fajl at predostavlyaet mehanizm dlya vypolneniya zadach, svyazannyh so vremenem. My mozhem skazat' sisteme, chto i kogda my hotim sdelat'. Zadacha ostaetsya "spyashchej" v fonovom rezhime do naznachennogo vremeni. |to daet nam vozmozhnost' prevratit' komp'yuter v budil'nik, sekretarya, administratora vstrech i t.d. Dannaya koncepciya ne nova i uzhe sushchestvuet v sisteme Berkeley UNIX pod tem zhe imenem. Ona realizovana takzhe v poslednih versiyah System V. Pochemu zhe togda my predstavlyaem zdes' nashu sobstvennuyu versiyu? Odna iz prichin v tom, chto mnogie iz vas imeyut bolee rannie versii UNIX, v kotoryh eto sredstvo otsutstvuet. No vazhnee, vidimo, drugoe - nasha cel' ne v tom, chtoby sdelat' sushchestvuyushchie komandy at ustarevshimi, a v pokaze togo, kak legko otslezhivat' vremya i realizovyvat' obrabot- ku, svyazannuyu so vremenem. Imeya nashu sobstvennuyu komandu at, my mozhem nastroit' ee po svoemu vkusu i izmenit' ee, kogda neobhodimo. Komanda at, predstavlennaya zdes', fakticheski bolee gibkaya, chem at v sisteme Berkeley, hotya v pervoj otsutstvuyut nekotorye osobennosti vtoroj. Ona bolee gibkaya potomu, chto vy mozhete pomestit' nastoyashchie komandy v fono- vuyu zadachu at, v to vremya kak dlya at v sisteme Berkeley vy dolzhny ispol'zovat' imya komandnogo fajla interpretatora shell. Metod Berkeley zapreshchaet vam vyzyvat' ispolnyaemye moduli neposredstvenno v komandnoj stroke, a nasha at - net. (Konechno, vy mozhete s takim zhe uspehom ispol'zovat' komandnye fajly interpretatora shell, esli vam eto neob- hodimo.) CHTO DELAET at? Komanda at daet nam vozmozhnost' sobirat' neskol'ko komand v odno celoe i vposledstvii zapuskat' ih. Kogda oni vypolnyayutsya, ih vyvod mo- zhet libo idti na ekran, libo perenapravlyat'sya v opredelennyj fajl. Komandnaya stroka prinimaet dva parametra: vremya vypolneniya i ko- mandnuyu stroku, kotoruyu sleduet vypolnit'. Vremya vyrazheno v formate chas:minuta. CHas dolzhen byt' ukazan strokoj iz dvuh cifr (v diapazone ot 0 do 23 chasov), tak kak ego ispol'zuet komanda date. Ispol'zovanie togo zhe standarta, chto i v komande date, znachitel'no uproshchaet komandu at. V kachestve vtorogo parametra mozhet byt' lyubaya komanda, kotoruyu obychno mozhno vvesti v komandnoj stroke interpretatora shell. Mozhno takzhe ispol'zovat' konvejery, sostavnye komandy i perenaznacheniya. Net ogranichenij na to, kakaya komanda mozhet byt' vypolnena. Komanda at mo- zhet zapustit' obychnyj ispolnyaemyj modul' UNIX ili vash sobstvennyj ko- mandyj fajl. Vyhod at po umolchaniyu napravlyaetsya v standartnyj vyvod. Standart- nym vyvodom v dannom sluchae yavlyaetsya ekran terminala. Komanda at v sisteme Berkeley ne imeet vyvoda po umolchaniyu, chto neskol'ko zatrudnya- et poluchenie rezul'tata i otpravku ego na ekran. Komanda at vsegda zapuskaetsya kak fonovaya zadacha. Necelesoobrazno zapuskat' ee v prioritetnom rezhime, gde ona blokiruet terminal na vse vremya svoego vypolneniya. Prebyvaya v fonovom rezhime, at osvobozhdaet resursy, no vse zhe rabotaet dlya vas. Mezhdu prochim, otmetim, chto kogda processy stavyatsya v fonovyj rezhim iznutri komandnogo fajla, identifi- kator processa ne pechataetsya na ekran, kak eto proishodit, kogda pro- cessy zapuskayutsya v fonovom rezhime s klaviatury. Porozhdenie bol'shogo kolichestva fonovyh processov mozhet imet' ot- ricatel'nyj effekt dlya sistemy. Kazhdaya fonovaya zadacha - eto cikl while interpretatora shell, kotoryj rabotaet ochen' medlenno. Kogda mnogo fo- novyh processov, malo vremeni central'nogo processora ostaetsya na dru- gie celi. V rezul'tate proizvoditel'nost' sistemy uhudshaetsya. V bol'- shih sistemah eto, veroyatno, ne problema, esli tol'ko sistema ne zagru- zhena mnozhestvom pol'zovatelej, no vy dolzhny ispol'zovat' eto sredstvo s ostorozhnost'yu. Otmetim, chto format chas:minuta goditsya tol'ko dlya odnogo polnogo dnya. Dannaya programma at zadumana kak ezhednevnaya i ne imeet sredstv zapuska v opredelennyj den' ili mesyac, hotya vy mozhete legko rasshirit' ee, kak tol'ko pojmete, kak chitaetsya i ispol'zuetsya informaciya o vre- meni. PRIMERY 1. $ at 11:45 echo ^G^G It's almost lunch time Bez pyatnadcati minut dvenadcat' dvazhdy vydaetsya zvukovoj signal (control-G) i vyvoditsya soobshchenie o lenche. 2. $ at 10:45 "if [ -s $MAIL ]; then echo ^G You have mail; fi" Bez pyatnadcati odinnadcat' proveryaetsya, sushchestvuet li moj pochto- vyj fajl i est' li v nem hotya by odin simvol ($MAIL est' /usr/spool/mail/russ). Esli eto tak, vydaetsya zvukovoj signal i soob- shchenie o tom, chto u menya est' pochta. 3. $ at 17:00 "c; date; banner ' time to' ' go home'" V pyat' chasov vechera ochishchaetsya ekran (s pomoshch'yu komandy c, opisan- noj dalee v dannoj knige), pechataetsya data i vyvoditsya krupnymi bukva- mi na ves' ekran soobshchenie "time to go home" ("pora domoj"). S pomoshch'yu apostrofov v komandnoj stroke banner my mozhem dobit'sya vyvoda simvola vozvrata karetki, chtoby razmestit' kazhdyj nabor slov v otdel'noj stro- ke. Esli kakaya-libo iz etih komand ne srabatyvaet (naprimer, ne najde- na komanda c), to i ves' fonovyj process okanchivaetsya neudachej. POYASNENIYA Prezhde vsego at proveryaet, pravil'no li ona byla vyzvana. Stroki 4-8 delayut proverku oshibok. V komandnoj stroke dolzhny prisutstvovat' po krajnej mere dva parametra: vremya i komanda. Esli eto tak, to schet- chik pozicionnyh parametrov raven 2. Esli etot schetchik men'she 2, proi- zoshla oshibka. V standartnyj fajl oshibok posylayutsya soobshcheniya ob oshibke s pomoshch'yu pereadresacii v fajlovyj deskriptor 2. Peremennaya interpretatora shell ITS inicializiruetsya v stroke 10. V nej ustanavlivaetsya znachenie pervogo pozicionnogo parametra ($1), kotorym yavlyaetsya chas:minuta. Kak tol'ko my zanesli eto znachenie v pe- remennuyu, ono bol'she ne nuzhno nam v komandnoj stroke. Komanda shift udalyaet $1 iz komandnoj stroki. Teper' komandnaya stroka sostoit iz vy- zyvayushchej komandy $0 (t.e. samoj at) i ostatka stroki ($@ ili $*). Vy- zyvayushchaya komanda ne vychislyaetsya kak chast' ostatka stroki, poetomu vam ne nuzhno zabotit'sya ob argumente $0. Dalee at perehodit k vechnomu ciklu while v strokah 12-21. Vechnym etot cikl delaet komanda : (dvoetochie). |to vstroennaya komanda interp- retatora shell, kotoraya nichego ne delaet krome togo, chto vsegda vozv- rashchaet uspeshnyj status vyhoda, zastavlyaya tem samym cikl prodolzhat'sya. Komanda true interpretatora shell ochen' pohozha i delaet programmu bo- lee naglyadnoj. My zhe ispol'zuem : vmesto true, chtoby sokratit' izderzh- ki na porozhdenie processa dlya kazhdoj iteracii cikla. Komanda : vstroe- na v sam shell. True, naprotiv, yavlyaetsya vneshnej komandoj v kataloge bin (tak zhe, kak ls), ona dolzhna byt' najdena po fajlovomu puti, vy- polnit'sya i vernut' znachenie. |to zanimaet gorazdo bol'she processorno- go vremeni. Na kazhdoj iteracii cikla tekushchee vremya sveryaetsya s naznachennym vremenem, peredannym iz komandnoj stroki. Tekushchee vremya izvlekaetsya iz komandy date v stroke 14. Obychno date vydaet rezul'tat v takom forma- te: ---------------------------- | | Mon Mar 31 06:54:25 PST 1986 | | Poskol'ku eto stroka fiksirovannogo razmera, my mozhem poschitat' nomera pozicij, v kotoryh razmeshcheny chas i minuta. Dannye chas:minuta nahodyatsya v poziciyah 12-16. Dlya polucheniya etih simvolov my zapuskaem komandu date, propuskaem ee rezul'tat po konvejeru cherez cut i vyreza- em nuzhnye pozicii. Ves' rezul'tat prisvaivaetsya peremennoj TIME. Zame- tim, chto pole sekund ne ispol'zuetsya. Naimen'shaya edinica vremeni v etoj programme - minuta. Vse volshebstvo dannoj komandy zaklyucheno v strokah 16-20. Esli vremya, ukazannoe v komandnoj stroke, ravno tekushchemu vremeni (stroka 16), vychislit' i vypolnit' ostal'nye argumenty komandnoj stroki (stro- ka 17), zatem vyjti s uspeshnym nulevym znacheniem (stroka 18). Esli vremya ne sovpalo, nemnogo pospat' (stroka 19) i povtorit' vse snachala. Simvol & v konce cikla v stroke 21 prevrashchaet ves' cikl while v fonovyj process. Kak my mozhem ubedit'sya, chto shell vypolnyaet vse svoi komandy v fonovom rezhime i nikakie iz nih ne vypolnyaet v operativnom rezhime? V dejstvitel'nosti my ne mozhem etogo sdelat'. My dolzhny pola- gat', chto shell tak rabotaet. Poskol'ku mnogoe pri programmirovanii na shell delaetsya ishodya iz opyta i intuicii, vam prihoditsya ispytyvat' mnogie veshchi, chtoby uvidet', kak oni rabotayut. Periodicheski shell pre- podnosit syurprizy i delaet nechto sovershenno neozhidannoe. ISSLEDOVANIYA CHto by sluchilos', esli by vy postavili zadanie at v fonovyj re- zhim, a zatem vyshli iz sistemy? Otvet zavisit ot togo, s kakim shell vy rabotaete. Esli u vas Bourne shell, to vvod komandy control-D pri vy- hode iz sistemy prekrashchaet vypolnenie vseh vashih fonovyh zadach. Edinstvennyj sposob ostavit' v zhivyh fonovye zadachi posle vyhoda iz sistemy - ispol'zovat' komandu nohup ("no hang up" - "ne kaznit'"). Nohup obespechivaet, chto vse signaly o prekrashchenii processa ne dostiga- yut dannogo processa. Ne poluchaya signal o prekrashchenii vypolneniya, pro- cess dumaet, chto vy vse eshche nahodites' v sisteme. Sintaksis vyglyadit tak: nohup at 13:00 echo "back from lunch yet?" Esli vy zapuskaete Si-shell, vse fonovye processy prodolzhayutsya posle vashego vyhoda iz sistemy. Prichina v tom, chto Si-shell perevodit vse svoi fonovye zadachi v sostoyanie zashchity ot prekrashcheniya vypolneniya. |tot process avtomaticheskij, i ego ne nuzhno ukazyvat' yavno. Vy, vozmozhno, udivleny tem, chto v stroke 17 ispol'zovana komanda "eval $@". |to sformirovalos' metodom prob i oshibok. Na nachal'nyh eta- pah razrabotki at komanda "$@" ispol'zovalas' sama po sebe. Pri sa- mostoyatel'nom primenenii eta komanda oznachaet "vypolnit' vse pozicion- nye parametry". Poskol'ku eto byla edinstvennaya komanda, vypolnyalas' vsya stroka pozicionnyh parametrov, posle chego voznikali problemy. Ispol'zovanie perenaznachenij i peremennyh interpretatora shell sil'no zaputyvalo at. Dlya illyustracii rassmotrim paru primerov. Esli my zapuskaem at s komandnoj strokoj at 09:30 echo $HOME to vse vrode by rabotaet. Snachala raskryvaetsya peremennaya $HOME, zatem echo pechataet ee znachenie - /usr/russ. No esli my zapuskaem komandnuyu stroku at 09:30 echo \$HOME to peremennaya ne raskryvaetsya i echo fakticheski pechataet $HOME vmesto znacheniya peremennoj $HOME. My izbezhali etogo prosto s pomoshch'yu komandy eval dlya povtornogo vychisleniya komandnoj stroki pered ee vypolneniem. Sushchestvo problemy v tom, chto vyzyvayushchij interpretator shell ne raskry- vaet znachenie peremennoj, poetomu my zastavlyaem vypolnyayushchijsya shell povtorno analizirovat' komandnuyu stroku i vychislyat' vse peremennye. Na etot raz znacheniya peremennyh raskryvayutsya, i my poluchaem vernyj konech- nyj rezul'tat. MODIFIKACII Vozmozhno, vy zahotite bolee podrobno rassmotret' interfejs so vremenem. V nyneshnem sostoyanii at vosprinimaet tol'ko vremya v predelah ot 0 do 23 chasov v techenie odnogo dnya. Neplohim dopolneniem bylo by zastavit' ego razlichat' vremya sutok, t.e. 8:30 a.m. (do poludnya) ili 8:30 p.m. (posle poludnya). Bylo by neploho takzhe imet' vozmozhnost' skazat' "cherez 10 minut sdelat' to-to i to-to". V etom sluchae komanda mogla by imet' primerno takoj vid: at -n 10 echo "do in now plus 10 minutes" gde -n bylo by tekushchim vremenem, a 10 dobavlyalos' by k nemu. Drugoj ochevidnoj oblast'yu modifikacii yavlyaetsya nadelenie at voz- mozhnost'yu zapominaniya periodov vremeni, prevyshayushchih sutki. |to mozhet byt' zavtrashnij den', opredelennyj den' ili dazhe opredelennyj mesyac. Rabota s opredelennym mesyacem mozhet byt' ne sovsem real'noj, poskol'ku komandnyj fajl, vypolnyaemyj v fonovom rezhime v techenie neskol'kih mesyacev, potrebuet gromadnogo kolichestva processornogo vremeni, a tak- zhe hraneniya postoyanno vozrastayushchego schetchika identifikatorov pro- cessov, chto dast, veroyatno, pol'zovatelyam iskazhennoe predstavlenie ob aktivnosti sistemy. Po dostizhenii maksimal'nogo nomera processa, snova vernutsya mladshie nomera, tak chto eto ne privedet k kakim -libo ser'ez- nym posledstviyam. Reshenie voprosa o tom, stoit li takoj cenoj dosti- gat' vashej celi, zavisit ot togo, schitaete li vy, chto vashi trebovaniya izlishne zagruzhayut sistemu. ------------------------------------------------------------- IMYA: b -------------------------------------------------------------- b Obrabotchik fonovyh zadach FORMAT VYZOVA b any_command_with_options_and_arguments (lyubaya komanda s opciyami i argumentami) PRIMER VYZOVA b cg f.c Kompilirovat' ishodnyj fajl v fonovom rezhime, gde cg - komandnaya stroka kompilyatora, opisannaya v glave 10. TEKST PROGRAMMY b 1 : 2 # @(#) b v1.0 Background task handler Author: Russ Sage 2a Obrabotchik fonovyh zadach 4 ($@; echo "^G\ndone\n${PS1}\c") & OPISANIE ZACHEM NAM NUZHEN b? Kak vy videli v poslednem razdele, Bourne shell daet vozmozhnost' zapuskat' zadachi v fonovom rezhime vypolneniya. |to delaet simvol &. CHto zhe na samom dele proishodit, kogda my zapuskaem chto-nibud' v fonovom rezhime? Porozhdaetsya eshche odin shell, kotoryj dolzhen vypolnit' svoyu sobstvennuyu komandnuyu stroku. Posle togo, kak vse ego komandy vypol- nyatsya, on zavershaetsya. Vy mozhete opredelit' fonovye zadachi po rezul'- tatu raboty komandy ps. |ti zadachi vyglyadyat kak interpretatory shell, zapushchennye s vashego terminala, odnako ih vladel'cem, ili roditel'skim processom v dejstvitel'nosti yavlyaetsya komanda init, a ne vash registra- cionnyj shell (eto spravedlivo tol'ko dlya shell, k kotorym primenena komanda nohup). Interpretatory shell, k kotorym ne primenyalas' nohup, prinadlezhat vashemu registracionnomu shell. Nizhe privoditsya primer raspechatki komandy ps dlya fonovyh zadach. Komandoj dlya vypolneniya v fo- novom rezhime byla: while :;do date; done & Komanda ps pokazyvaet moj registracionnyj shell (PID=32), vveden- nuyu mnoj komandnuyu stroku dlya vypolneniya v fonovom rezhime (PID=419) i shell, kotoryj vypolnyaet cikl while (PID=449). ----------------------- | | UID PID PPID C STIME TTY TIME COMMAND | | root 0 0 0 Dec 31 ? 0:03 swapper | root 1 0 0 Dec 31 ? 0:02 /etc/init | russ 32 1 0 14:18:36 03 1:26 -shV | russ 419 32 0 15:30:31 03 0:02 -shV | russ 449 419 2 15:30:31 03 0:02 -shV | Nizhe priveden listing komandy ps, kotoryj pokazyvaet fonovyj shell, prinadlezhashchij processu init. On byl poluchen komandoj "b ps -ef", gde b - utilita, kotoraya budet rassmotrena dalee. Kak vidite, poslednij process 471 est' fonovyj shell, prinadlezhashchij processu 1, kotorym yavlyaetsya init, a ne moj registracionnyj shell (PID=32). ------------------------- | | UID PID PPID C STIME TTY TIME COMMAND | root 0 0 1 Dec 31 ? 0:04 swapper | root 1 0 0 Dec 31 ? 0:02 /etc/init | russ 32 1 1 14:18:36 03 1:30 -shV | russ 472 471 5 15:46:46 03 0:12 ps -ef | russ 471 1 0 15:46:46 03 0:00 -shV | K chemu vse eto privodit? Kogda my ispol'zuem fonovye zadachi, my dolzhny mirit'sya s "nerazborchivost'yu" pri upravlenii asinhronnymi pro- cessami. Kakovy eti nedostatki? Vo-pervyh, my nikogda ne znaem momenta zaversheniya fonovyh zadach. Edinstvennyj sposob opredelit' moment zaversheniya takih zadach - prover- ka rezul'tatov v kakom-libo fajle ili nekotoroj raboty, vypolnennoj zadachej, ili ispol'zovanie komandy ps i postoyannoe slezhenie za tem, kogda process zavershitsya. Takoe slezhenie pri pomoshchi komandy ps - ne samyj luchshij sposob, poskol'ku ps zanimaet mnogo processornogo vremeni i ochen' medlenno rabotaet. Vtoroj neakkuratnyj moment - eto simvol priglasheniya posle vydachi na vash ekran rezul'tata iz fonovoj zadachi. Posle togo kak vydan re- zul'tat iz fonovoj zadachi, vash registracionnyj shell ozhidaet vvoda ko- mandy, no priglasheniya mozhet i ne byt', poskol'ku ono bylo udaleno s ekrana nekotorym drugim soobshcheniem. Vy mozhete ozhidat' priglasheniya ce- lyj den', no ono nikogda ne poyavitsya, poskol'ku ono uzhe bylo vyvedeno na ekran. Vy prosto dolzhny znat', chto shell zhdet vashu komandu. Nam neobhodimo instrumental'noe sredstvo, kotoroe soobshchaet nam o zavershenii fonovoj zadachi, a takzhe vosstanavlivaet nash ekran posle vy- dachi na nego kakih-libo rezul'tatov. Mozhem li my skazat', vypolnyala li vyvod na ekran fonovaya zadacha ili net? Net, poetomu my dolzhny zhestko zaprogrammirovat' vosstanovlenie ekrana v programme. CHTO DELAET b? Komandnyj fajl b - eto mehanizm, kotoryj pomogaet v vypolnenii fonovyh zadach. On zapuskaet nashi fonovye zadachi. Po zavershenii on otobrazhaet na ekran slovo "done" i zatem povtorno vyvodit simvol-prig- lashenie shell. Dannoe sredstvo ne imeet opcij i proverki na nalichie oshibok. Ob- rabotchik fonovyh zadach fakticheski vypolnyaet komandnuyu stroku, kotoruyu my emu peredaem, i posleduyushchuyu obrabotku. Otmetim, chto dlya vydachi na ekran vashego simvola priglasheniya, vy dolzhny eksportirovat' peremennuyu PS1 iz vashej tekushchej sredy. |to mozhet soblyudat'sya ne na vseh mashinah, poskol'ku kazhdaya sistema UNIX imeet svoi osobennosti. V sisteme XENIX peremennaya PS1 ne peredaetsya, vozmozhno iz-za togo, chto eto shell, ko- toryj vyzyvaet drugoj shell v fonovom rezhime. Esli vy skazhete "sh" v interaktivnom rezhime, on budet peredan kak priglashenie. Sistema UNIX tak prekrasna i udivitel'na! PRIMERY 1. $ b ls -R .. Nachinaya s roditel'skogo kataloga, rekursivno sostavlyaetsya spisok vseh fajlov i vyvoditsya na ekran. Obratite vnimanie, chto pri ispol'zo- vanii fonovyh zadach vy ne mozhete effektivno peredat' vse eto po konve- jeru komande more, poskol'ku obychnym vhodnym ustrojstvom dlya fonovyh zadach yavlyaetsya /dev/null. Komanda more ne rabotaet normal'no, kogda ee vyzyvayut iz fonovogo rezhima. |to takzhe imeet smysl, poskol'ku vy mogli by imet' dve zadachi - odnu v fonovom rezhime, a druguyu v prioritetnom - proizvodyashchie besporyadok na ekrane. Fonovaya komanda more dolzhna byla by sohranyat' v neprikosnovennosti to, chto vyvodit na ekran prioritetnaya komanda. 2. $ b echo hello > z Fajl z soderzhit ne tol'ko slovo "hello", no takzhe i soobshchenie "done", poskol'ku pereadresaciya v fajl z vypolnyaetsya vo vneshnem shell. Pereadresaciya dlya podzadachi dolzhna byt' vypolnena v kruglyh skobkah programmy b, a my v dannom sluchae ne mozhem etogo sdelat'. 3. $ b sleep 5; echo hello |ta komandnaya stroka ne mozhet byt' vypolnena, poskol'ku programma b vosprinimaet tol'ko komandu sleep. Komanda echo ne pomeshchaetsya v fo- novyj process i srazu zhe vypolnyaetsya. 4. $ b "sleep 5; echo hello" |tu komandnuyu stroku my tozhe ne mozhem vypolnit', poskol'ku eti dve komandy budut vosprinyaty komandnym fajlom b kak odna. Zatem koman- da sleep ne vypolnitsya, poskol'ku "5; echo hello" yavlyaetsya nedopusti- mym ukazaniem vremennogo perioda dlya komandy sleep. POYASNENIYA Obratite vnimanie, chto v stroke 4 vsya struktura komandy zaklyuchena v kruglye skobki, za kotorymi sleduet simvol &. Kruglye skobki pereda- yut vsyu strukturu podchinennomu shell, kotoryj zatem pomeshchaetsya v fono- vyj rezhim vypolneniya. Pomeshchaya vse komandy v odin shell, my garantiruem vyvod na ekran slova "done" posle zaversheniya poslednego processa. Dannaya komandnaya stroka vypolnyaetsya s pomoshch'yu simvolov $@. |to oznachaet: "vypolnit' vsyu komandnuyu stroku, raspolozhennuyu sprava". Poskol'ku vyrazhenie $@ vypolnyaet samo sebya (t.e. ne v operatore echo ili v chem-libo podobnom), to shell prosto vypolnyaet komandy ishodnoj komandnoj stroki. |to imenno to, chto my hotim! Obratite vnimanie, chto zdes' net nikakogo operatora eval. Poskol'ku to, chto my delaem, pohozhe na svoego roda "komandnyj interpretator strok" dlya ih vvoda i ispolne- niya, vy mogli by podumat', chto komanda eval zdes' neobhodima. Po opytu my znaem, chto eto ne tak. Pohozhe, chto primenenie eval uslozhnit delo. Dazhe nash staryj test, ispol'zuyushchij peremennye sredy vypolneniya, rabo- taet. Po komande b echo $HOME na ekran budet vydano soobshchenie /usr/russ Kogda vsya komanda vypolnitsya, podaetsya zvukovoj signal i vyvo- ditsya soobshchenie, informiruyushchee pol'zovatelya o tom, chto operaciya zaver- shilas'. Poskol'ku eto soobshchenie nakladyvaetsya na to, chto bylo na ekra- ne, to pereotobrazhaetsya nachal'nyj simvol priglasheniya (PS1). |to delaet normal'nym vid ekrana v tom smysle, chto simvol priglasheniya shell soob- shchaet ob ozhidanii vvoda. --------------------------------------------------------- IMYA: greet --------------------------------------------------------- greet Svoevremennoe privetstvie s terminala NAZNACHENIE Opredelenie vremeni sutok i pechat' privetstviya i kakogo-libo soobshcheniya na terminal v zavisimosti ot vremeni dnya. FORMAT VYZOVA greet PRIMER VYZOVA greet Vyzyvaet komandnyj fajl greet, kotoryj opredelyaet vremya i pechataet sootvetstvuyushchee soobshchenie. TEKST PROGRAMMY greet 1 : 2 # @(#) greet v1.0 Timely greeting from the terminal Author: Russ Sage 2a Svoevremennoe privetstvie s terminala 4 if [ `expr \`date +%H\` \< 12` = "1" ] 5 then echo "\nGood morning.\nWhat is the best use of your time right now?" 6 elif [ `expr \`date +%H\` \< 18` ="1" ] 7 then echo "\nGood afternoon.\nRemember, only handle a piece of paper once!" 8 else echo "\nGood evening.\nPlan for tomorrow today." 9 fi OPISANIE ZACHEM NAM NUZHEN greet? Odnim iz zamechatel'nyh preimushchestv mnogopol'zovatel'skih operaci- onnyh sistem yavlyaetsya to, chto oni imeyut horosho razvituyu koncepciyu vre- meni. Obychno oni soderzhat chasy real'nogo vremeni i nekotoroe programm- noe obespechenie, kotoroe manipuliruet s nimi. Odnako vsegda est' mesto dlya dopolnitel'nogo programmnogo obespecheniya, rabotayushchego so vremenem. Takie sredstva mogut byt' napisany kak na yazyke Si, tak i na shell-yazyke. Kak my izvlekaem i vydelyaem vremya s pomoshch'yu komandnogo fajla in- terpretatora shell? Dostupno mnogo sposobov, no standartnaya komanda UNIX date, vidimo, yavlyaetsya nailuchshim sposobom. V sluchae yazyka Si vy dolzhny programmno upravlyat' preobrazovaniem vremeni i vremennymi zona- mi. Komanda date delaet eto dlya vas. Vazhna takzhe edinica vremeni. Dolzhny li my razlichat' sekundy, mi- nuty, chasy, dni ili nedeli? |to vse zavisit ot trebuemogo prilozheniya. V nashem prostom primere my razlichaem tol'ko tri chasti sutok: utro, den' i vecher. My opredelili eti periody tak: s polunochi do poludnya, ot poludnya do shesti chasov i ot shesti chasov do polunochi sootvetstvenno. CHTO DELAET greet? Greet - eto utilita, kotoraya privetstvuet pol'zovatelya razlichnymi soobshcheniyami v zavisimosti ot vremeni sutok. Vyvodimye soobshcheniya ne tak vazhny. Oni v osnovnom ispol'zovany kak primery, pokazyvayushchie, kak mo- gut byt' vypolneny kakie-to komandy. Esli vy rabotaete v odinochestve i hoteli by poboltat', eti soobshcheniya mogli by chitat'sya periodicheski iz sootvetstvuyushchih fajlov dlya sozdaniya illyuzii avtomaticheskoj pis'mennoj boltovni v zavisimosti ot vremeni sutok. Dejstvitel'noj zhe cel'yu yavlyaetsya sozdanie karkasa programmy, ko- toraya mozhet pereklyuchat'sya v zavisimosti ot parametrov vremeni. Putem rasshireniya koncepcii vremeni vy mozhete sozdat' drugie utility, kotorye znayut, kogda im rabotat' (v kakoj promezhutok vremeni) i mogut vesti sebya inache v sootvetstvii so vremenem. Greet ne trebuet nichego v komandnoj stroke. Ne vypolnyaetsya nika- koj proverki na nalichie oshibok, poetomu i net v programme sintaksi- cheskoj podskazki. Vyhod komandy greet mozhet byt' pereadresovan v fajl ili peredan po konvejeru drugomu processu. PRIMERY 1. $ if greet | fgrep 'morn' > /dev/null > then morning_routine > fi Vypolnyaetsya greet. Standartnyj vyvod greet po konvejeru pereda- etsya na standartnyj vvod fgrep. Proizvoditsya poisk simvol'noj stroki "morn". Ves' vyhod pereadresovyvaetsya v nikuda, tak chto on ne zasoryaet ekran. Esli vyhodnoj status komandy fgrep raven nulyu (ona nashla nuzhnuyu stroku), vypolnyaetsya fajl morning_routine. 2. $ at 10:30 greet; at 13:50 greet Vy mogli by vstavit' eto v vash .profile. Dva processa at budut vypolnyat'sya na vashej mashine v fonovom rezhime do teh por, poka ne nastupit vremya ih zapuska - togda oni poprivetstvuyut vas na vashem ter- minale. Pravda, eto mozhet prichinit' nebol'shoe neudobstvo. Soobshchenie mozhet poyavit'sya, kogda vy rabotaete v redaktore, i narushit' soderzhimoe ekrana, no na samom dele ono ne izmenit vash redaktiruemyj fajl. POYASNENIYA Vsya programma predstavlyaet soboj odin bol'shoj operator if -then-else v strokah 4-9. Logika programmy vyglyadit na psevdokode sle- duyushchim obrazom: if it is morning esli utro then echo morning statement to vyvesti "utrennee" privetstvie else if it is noon inache esli den' then echo noon statement to vyvesti "dnevnoe" privetstvie else echo evening statement inache vyvesti "vechernee" privetstvie V dejstvitel'nosti programma gorazdo slozhnee, poetomu perevedem dyhanie i pristupim k delu. V stroke 4 proveryaetsya tekushchee vremya na to, men'she li ono 12 chasov. Esli da, to fraza komandy expr vyvodit na standartnoe ust- rojstvo vyvoda edinicu ("1"). Poskol'ku simvoly udareniya (`), kotorye obramlyayut etu frazu, perehvatyvayut standartnyj vyvod, simvol 1 stano- vitsya chast'yu operatora proverki, chto ukazano kvadratnymi skobkami ([]). Zatem operator test proveryaet, raven li vyhod komandy expr lite- ral'noj edinice. Esli oni odinakovy, to v stroke 5 vyvoditsya "utren- nee" soobshchenie. Rassmotrim bolee podrobno, kak raskryvaetsya operator expr. Vo-pervyh, on zaklyuchen v simvoly udareniya. |to oznachaet, chto on vypol- nyaetsya pered operatorom proverki. Zatem ego vyhod pomeshchaetsya dlya obra- botki v operator test. Odnako vnutri operatora expr imeetsya eshche odno vyrazhenie mezhdu znakami udareniya, kotoroe vypolnyaetsya do operatora expr. Takoe starshinstvo vypolneniya upravlyaetsya interpretatorom koda vnutri shell. Vnutrennie znaki udareniya sohranyayutsya pri nachal'nom sintaksi- cheskom razbore stroki, poskol'ku oni ekranirovany simvolami obratnoj kosoj cherty. Pervoj zapuskaetsya komanda date, imeyushchaya v kachestve vyho- da tol'ko tekushchee znachenie chasa v sootvetstvii s formatom %H. Zatem expr ispol'zuet dannoe znachenie chasa dlya proverki, men'she li ono 12. Esli da, expr pechataet edinicu. Esli znachenie chasa bol'she ili ravno 12, to vozvrashchaemoe znachenie ravno 0. Takoe ponimanie, chto 1=istina i 0=lozh', sootvetstvuet sintaksisu, ispol'zuemomu v yazyke Si. Odnako ranee my zamechali, chto v srede programmirovaniya na yazyke shell 1 oznachaet lozh', a 0 - istinu. |to proishodit potomu, chto prove- ryaemoe znachenie operatora if yavlyaetsya v dejstvitel'nosti statusom vy- hoda iz predvaritel'no vypolnennoj komandy. Nul' sootvetstvuet nor- mal'nomu zaversheniyu, poetomu 0 ispol'zovan dlya pereklyucheniya proverki v sostoyanie "istina" i vypolneniya operatora then. Dlya togo, chtoby preob- razovat' vozvrashchaemyj status 1 (pri uslovii, chto znachenie chasa men'she 12) v nul' (dlya pereklyucheniya operatora then), my ispol'zuem komandu test. Vozvrashchaemyj status edinicy raven konstante 1, poetomu komanda test vozvrashchaet 0, chto predstavlyaet istinu. Vot tak! Esli by ne byli ispol'zovany vlozhennye znaki udareniya, to edinstvennym sposobom peredachi dannogo tipa informacii drugomu pro- cessu bylo by primenenie peremennyh shell. Ispol'zovanie vlozhennoj ko- mandnoj podstanovki daet nam bol'shuyu gibkost' i prostotu programmiro- vaniya. CHem bol'she glubina vlozhennosti, tem glubzhe ekranirovanie znakov udareniya. Poryadok ekranirovaniya simvolami obratnoj kosoj cherty takoj: ne nuzhno dlya vneshnej komandy, odin raz dlya vtoroj vnutrennej komandy, pyat' raz dlya tret'ej vnutrennej komandy. Na chetvertom urovne ih dolzhno byt' sem' ili devyat' (ya eshche ne proboval), no veroyatno net bol'shoj nuzh- dy vo vlozhennosti takoj glubiny. Esli proverka v stroke 4 daet "lozh'", vypolnyaetsya stroka 6. |to operator else ot pervogo if i odnovremenno sleduyushchij if. V takih oso- byh sluchayah sintaksis shell menyaetsya. Klyuchevoe slovo "else" stanovitsya klyuchevym slovom "elif". Vtoroj if ispol'zuet komandu test tochno tak zhe, kak i pervyj. Proveryaemoe vremya zdes' 18, chto predstavlyaet soboj 6 chasov vechera. Esli vtoraya proverka takzhe daet "lozh'", vypolnyaetsya poslednij operator v stroke 8. |tot else ne ispol'zuet komandu test, poskol'ku posle vy- polneniya pervyh dvuh proverok my mozhem sdelat' vyvod, chto ostalsya poslednij period vremeni, a imenno period posle 18:00. -------------------------------------------------------- IMYA: lastlog -------------------------------------------------------- lastlog Soobshchaet vremya poslednej registracii NAZNACHENIE Zapisyvaet i vyvodit na ekran den' i vremya vashej poslednej re- gistracii v sisteme. FORMAT VYZOVA lastlog [-l] PRIMER VYZOVA lastlog Pechataet datu, kogda vy poslednij raz registrirovalis' TEKST PROGRAMMY lastlog 1 : 2 # @(#) lastlog v1.0 Report last login time Author: Russ Sage 2a Soobshchaet vremya poslednej registracii 4 if [ $# -gt 1 ] 5 then echo "lastlog: arg error" >&2 6 echo "usage: lastlog [-l]" >&2 7 exit 1 8 fi 10 if [ "$#" -eq "1" ] 11 then if [ "$1" = "-l" ] 12 then date >> $HOME/.lastlog 13 lastlog 14 else echo "lastlog: unrecognized option $1" >&2 15 echo "usage: lastlog [-l]" >&2 16 exit 1 17 fi 18 else echo "Time of last login : `tail -2 $HOME/.lastlog | 19 (read FIRST; echo $FIRST)`" 20 fi PEREMENNYE SREDY VYPOLNENIYA FIRST Hranit pervuyu iz dvuh vvedennyh strok HOME Hranit imya vashego registracionnogo kataloga OPISANIE ZACHEM NAM NUZHEN lastlog? Odnim iz preimushchestv raboty v sisteme UNIX yavlyaetsya to, chto v nej sovershaetsya avtomaticheskaya zapis' vashego nachal'nogo vremeni pri kazhdom seanse raboty - vashego vremeni registracii. |ta informaciya mozhet byt' poleznoj po neskol'kim prichinam. Vopervyh, vy mozhete zapomnit', kogda vy dejstvitel'no rabotali v sisteme poslednij raz i proveryat', ne re- gistrirovalsya li kto-nibud' pod vashim parolem vo vremya vashego otsutstviya. Kak my uvidim v glave 9, imeetsya ryad vozmozhnostej dlya to- go, chtoby kto-nibud' mog "zaimstvovat'" vash parol' bez sprosa. Po etoj prichine mnogie kommercheskie sistemy soobshchayut vam, kogda vy registriro- valis' poslednij raz (ili kogda, po ih mneniyu, vy eto delali). Drugoj vozmozhnoj prichinoj mog by byt' podschet obshchego vremeni v konce seansa raboty. Vy mogli by ispol'zovat' eto kak uchetnuyu informa- ciyu dlya sebya ili vychislitel'nogo centra. Nemnogo pozzhe my predstavim sredstvo, kotoroe pomogaet pri takih podschetah. Razrabatyvaemoe nami instrumental'noe sredstvo dolzhno imet' voz- mozhnost' zapisyvat' novye znacheniya vremeni i vyvodit' na ekran vremya nashej poslednej registracii. Vazhno, chto dannaya programma mozhet byt' vyzvana tak, chto ona ne izmenyaet fajl s dannymi, no postoyanno vyvodit vremya poslednej registracii. CHTO DELAET lastlog? Lastlog - eto programma, kotoraya zapisyvaet vremya vashej registra- cii pri kazhdom vhode v sistemu. Zatem eto vremya hranitsya v fajle dan- nyh v vashem registracionnom kataloge pod imenem $HOME/.lastlog. Imya fajla lastlog nachinaetsya s tochki s toj cel'yu, chtoby sdelat' ego nevi- dimym dlya komandy ls. Ukrytie "sluzhebnyh" fajlov ot raspechatki po umolchaniyu neskol'ko predohranyaet ot lyubopytnyh glaz, a takzhe ubiraet eti fajly s dorogi, kogda vy prosmatrivaete chto-to drugoe. Pri vyzove bez opcij lastlog pechataet dlya nas datu poslednej re- gistracii, poluchaya zapis' iz fajla .lastlog. Dlya vypolneniya novoj zapisi v fajl .lastlog neobhodimo vyzvat' lastlog s opciej -l. Pri etom novoe znachenie vremeni zapishetsya v fajl .lastlog, a zatem komandnyj fajl lastlog vyzovet sam sebya dlya vyvoda na ekran novogo znacheniya - nebol'shaya rekursiya. Dlya togo, chtoby programma lastlog rabotala avtomaticheski, vy dolzhny vypolnyat' ee iz vashego fajla .profile vo vremya registracii. Pri takom sposobe ona zapishet poslednee vremya v fajl .lastlog. V kachestve primera posmotrite fajl .profile v pervoj glave. POYASNENIYA V strokah 4-8 vypolnyaetsya proverka na nalichie oshibok. Esli vy vyzvali lastlog s chislom argumentov bol'she odnogo, to eto privedet k oshibke. Vyvoditsya soobshchenie na standartnoe ustrojstvo registracii oshi- bok, i lastlog zavershaetsya so statusom oshibki 1. Stroki 10-20 predstavlyayut soboj operator if-then-else, kotoryj pokazyvaet, byl li eto vyzov dlya zapisi novogo znacheniya vremeni ili dlya pechati staryh znachenij. Esli v stroke 10 chislo pozicionnyh parametrov ravno odnomu, to my znaem, chto libo etot parametr dolzhen byt' opciej -l, libo eto oshibka. Sleduyushchij operator if v stroke 11 proveryaet, yavlyaetsya li pervyj pozi- cionnyj parametr opciej -l. Esli da, to v fajl $HOME/.lastlog dobavlya- etsya tekushchaya data i lastlog vyzyvaetsya snova bez argumentov dlya pechati predydushchej daty registracii. (My tol'ko chto videli, kak eto delaetsya.) Esli eto ne byl argument -l, to stroki 14-16 vypolnyayut obrabotku oshib- ki. Esli chislo pozicionnyh parametrov ravno nulyu, vypolnyaetsya opera- tor else v stroke 18. Otsutstvie opcij oznachaet, chto my hotim najti vremya nashej poslednej registracii na mashine i raspechatat' ego. |to ka- zhetsya dovol'no prostym, no kto skazal, chto mashiny prosty? Esli vy pomnite posledovatel'nost' raboty, to my sperva registri- ruem novoe vremya, a zatem hotim najti vremya nashej predydushchej registra- cii. Dlya fajla .lastlog eto oznachaet, chto nashe tekushchee vremya registra- cii nahoditsya v samom konce fajla, a nashe predydushchee vremya registracii nahoditsya v stroke neposredstvenno pered nim. |to znachit, chto my dolzh- ny poluchit' vtoruyu stroku ot konca fajla. Da uzh. Kak vidno iz stroki 18, ona zanimaetsya polucheniem poslednih dvuh strok. Komanda tail krasivo vypolnyaet etu rabotu. Nam nuzhen takoj sposob, chtoby my mogli prochitat' imenno pervuyu stroku, a vtoruyu otb- rosit', chto vypolnyaetsya v stroke 19. My peredaem po konvejeru vyhod komandy tail podchinennomu shell (ukazannomu kruglymi skobkami), koto- ryj chitaet pervuyu stroku i zatem otobrazhaet ee. A chto zhe so vtoroj strokoj? Ona nikogda ne beretsya i propadaet. Drugim sposobom mozhet byt' peredacha vyhoda komandy tail po konvejeru komande "head -1". Poskol'ku eta komanda ne imeet drugih opcij, my ne daem nikakih primerov. Tem ne menee, davajte teper' rassmotrim nashe drugoe sredstvo registracii vremeni vhoda v sistemu. -------------------------------------------------------- IMYA: timelog -------------------------------------------------------- timelog Uchet i statistika vremeni NAZNACHENIE Interfejsnoe menyu dlya slezheniya i soprovozhdeniya fajlov registracii vremeni. FORMAT VYZOVA timelog PRIMER VYZOVA timelog Vyvodit na ekran glavnoe menyu, iz kotorogo mozhno vybirat' neobhodimoe dejstvie TEKST PROGRAMMY timelog 1 : 2 # @(#) timelog v1.0 Time accounting and statistics Author: Russ Sage 2a Uchet i statistika vremeni 4 PROJ="" 6 while : 7 do 8 set `date` 9 echo " 11 $1, $2 $3 $4 13 Time Logger 14 ----------- Project: $PROJ 15 s) Select a project file 16 c) Create a new project file 17 l) List current project files 18 v) View the project file 19 n) Turn billing on 20 f) Turn billing off 21 r) Report ststistics 23 enter response (s,c,l,v,n,f,r,): \c" 25 read RSP 27 case $RSP in 28 "") break;; 29 s) echo "\Enter project name ( for exit): \c" 30 read PROJ2 31 if [ "$PROJ2" = "" ] 32 then continue 33 fi 34 if [ ! -s $PROJ2.time ] 35 then echo "you must specify a valid project file" 36 continue 37 fi 38 PROJ="$PROJ2";; 39 c) echo "\nEnter the new project name ( to exit): \c" 40 read PROJ2 41 if [ "PROJ2" = "" ] 42 then continue 43 fi 44 if [ -f "$PROJ2.time" ] 45 then echo "\n ** $PROJ2 already exists **" 46 continue 47 fi 48 PROJ="$PROJ2" 49 echo "\nProject file created: $PROJ" 50 echo "Project file created: `date`\nOFF: begin" > $PROJ.time;; 51 l) echo "\nCurrent project files:\n" 52 ls -l *.time 2>/dev/null || echo "no project files" | 53 sed "s/\.time//";; 54 v) if [ "$PROJ" = "" ] 55 then echo "you must select a project file first" 56 continue 57 fi 58 echo "\n:----------------------------" 59 more $PROJ.time 60 echo ":---------------------------";; 61 n) if [ "$PROJ" = "" ] 62 then echo "you must select a project file first" 63 continue 64 fi 65 if [ "`tail -1 $PROJ.time|cut -d: -f1`" != "OFF" ] 66 then echo "logging was not turned off" 67 continue 68 fi 69 echo "\nBilling turned on for project file: $PROJ" 70 echo "ON: `date`" >> $PROJ.time;; 71 f) if [ "$PROJ" = "" ] 72 then echo "you must select a project file first" 73 continue 74 fi 75 if [ "`tail -1 $PROJ.time|cut -d: -f1`" != "ON" ] 76 then echo "logging was not turned on" 77 continue 78 fi 79 echo "\nBilling turned off for project file: $PROJ" 80 echo "OFF: `date`" >> $PROJ.time;; 81 r) while : 82 do 83 echo " 84 Statistics 85 ---------- Project: $PROJ 86 a) Accumulative time totals 87 n) All times on 88 f) All times off 90 enter response (a,n,f,): \c" 92 read RSP 94 case $RSP in 95 "") break;; 96 a) awk '/Total:/ { PRINT $0 }' $PROJ.TIME;; 97 n) awk '/O