A4B33OSS: Semestrální práce B

Implementace skriptu v jazyce Bash

Úlohu řeší každý student samostatně. Vybírejte, z níže uvedených variant zadání. Vybrané zadání si rezervujte v odevzdávacím systému.

V případě jakýchkoliv nejasností v zadání se včas poraďte s vaším cvičícím. Včas řešte i případné problémy při implementaci úlohy. Důkladně si přečtěte jak zadání vaší varianty, tak společné pokyny!

Řešení úlohy odevzdáváte přes odevzdávací systém, který ji automaticky zkontroluje. Pokud systém vaší úlohu nepřijme, důkladně si prostudujte výsledek testu.

Obecná pravidla pro psaní skriptů

Při návrhu bash skriptu dbejte těchto zásad:

Nedodržení těchto zásad bude dle uvážení cvičícího penalizováno srážkou bodů!

UPOZORNĚNÍ: Z důvodu automatizované kontroly skriptů dále požadujeme implementace přepínače -v, který vypíše číslo řešené varianty na standardní výstup (a ukončí skript)!

Zadání variant

  1. Vytvořte shellovský skript, který v zadaném adresáři a jeho podadresářích najde všechny špatné symbolické odkazy (tj. všechny symbolické odkazy, které ukazují na neexistující soubor), vypíše jejich absolutní cestu na výstup (cestu k symlinku, ne k jeho cíli). Skript má dva nepovinné parametry: -r a -a. Pokud je zadán parametr -r pak chybný link smaže. Parametr -a vypíše všechny symbolické odkazy, nejen ty špatné, přičemž kombinace obou parametrů není přípustná. Pořadí všech parametrů (včetně cesty) může být libovolné. Pokud je v adresářové struktuře odkaz na adresář (platný), nenásledujte tento odkaz, tzn. neprohledávejte odkazovaný adresář.

    Pokud zadaný adresář neexistuje, nebo nenalezne žádný chybný link, vypíšete skript hlášení na chybový výstup. Není-li pracovní adresář zadán, pracuje skript v aktuálním adresáři.

    Př.: Výstup vašeho skriptu, který nalezne dva symbolické linky neex a wrong ukazující na neexistující soubory, nebo adresáře:

    /home/student/priklad/neex
    /home/student/priklad/wrong

    Nápověda: viz příkazy find, readlink, dirname.


  2. Vytvořte shellovský skript, který porovná dva tarované a gzipované archivy skupiny souborů. Pro každý soubor či adresář z každého archivu (i v podadresářích archivu) skript ověří, zda existuje soubor/adresář stejného jména v druhém archivu. V případě chybějícího podadresáře již nevypisujte soubory či podadresáře uvnitř něj. Skript na standardní výstup vypíše jména všech souborů, které nemají shodný ekvivalent v druhém archívu.

    Pokud některý ze zadaných souborů neexistuje, nebo není zadaný soubor tar gzip archív (nerozhodujte se podle přípony), vypíšete hlášení na chybový výstup.

    Př.: Výstup vašeho skriptu, který porovnává archívy arch1.tar.gz a arch2.tar.gz a nalezne rozdílné soubory aa/a.txt, bb/b.txt v arch1.tar.gz a soubor nic.txt a adresář dir1 v arch2.tar.gz:

    arch1.tar.gz:aa/a.txt
    arch1.tar.gz:bb/b.txt
    arch2.tar.gz:nic.txt
    arch2.tar.gz:dir1

    Podrobnější příklad na stránce s anglickým zadáním.

    Nápověda: viz příkaz tar. Uvědomte si také, že v tomto případě není nutné archiv rozbalovat.


  3. Vytvořte skript, který v zadaném adresáři a v jeho podadresářích vyhledá všechny soubory s danou příponou a podle parametru je
    • zkopíruje na soubory s jinou příponou, nebo
    • přejmenuje na soubory s jinou příponou, nebo
    • smaže.
    Skript bude mít 4 povinné parametry (3 v případě mazání souborů):
      adresar [ -c | -m | -r ] ext1 ext2,
    kde přípony ext1 a ext2 jsou běžné řetězce, které mohou (ale nemusí) obsahovat i znak tečka. Parametr -c určuje kopírování, -m přesun (přejmenování) a -r smazání souborů.

    Skript na standardní výstup vypíše pro kopírované i přesouvané soubory pro každý soubor řádku
    staré jméno => nové jméno
    přičemž pro smazané soubory bude vypsáno pouze jméno (resp. cesta) smazaného souboru.

    Na chybový výstup skript vypíše pokud zadaný adresář neexistuje, nebo pokud u některého souboru nebude mít skript práva na kopírování (právo na čtení), nebo právo na přesun (právo na čtení a psaní).

    Pokud bude některý z procesovaných souborů nečitelný nebo nezapisovatelný, vypište pouze chybové hlášení, ale návratovou hodnotu vracejte 0.

    Př.: Výstup pro příkaz s parametry adresář -c 'a.txt' 'ngz'

    a/aa.txt => a/angz
    a/ba.txt => a/bngz
    ta.txt => tngz

    Požadavky: blok programu pro procházení/hledání souborů se v kódu nebude opakovat.

    Nápověda: viz příkazy find, cp, mv a rm.

    Upozornění: vlastník souboru může soubor přejmenovat či smazat i v případě, že nemá nastavena oprávnění pro čtení či zápis. Kontrola příznaků r/w proto nemusí správně rozpoznat zda se zamýšlená operace provede či ne.


  4. Vytvořte skript, který pro zadaný adresář vytvoří, zataruje a gzipuje, zálohu tohoto adresáře a pojmenuje ji jméno_adresáře_číslo.tar.gz, kde číslo je nejnižší celé číslo od 0, pro které neexistuje soubor daného jména (nemusíte tedy hledat nejvyšší číslo). Zálohy skript vytváří buď v pracovním adresáři, nebo v adresáři, který je zadán jako druhý nepovinný parametr skriptu. Cesty v archivu musí být uloženy relativně k zadanému adresáři (uvnitř archivu tedy nesmí být cesta nadřazená zadanému adresáři) a to bez ohledu na to zda byl adresář zadán absolutně nebo relativně. Pozor na správné pojmenování zálohy, pokud zadaná cesta vede do nadřazeného adresáře (..).

    Výstup vašeho skriptu bude pouze na chybový výstup pokud některý ze zadaných adresářů neexistuje, nebo pokud nelze vytvořit zálohu. V případě úspěšného vytvoření archivu zobrazte na chybový výstup cestu k němu.

    V případě, že některý soubor v zálohovaném adresáři nelze číst, program vypíše chybu na chybový výstup, musí však dokončit zálohu zbývajících souborů. Návratová hodnota skriptu v tomto (a žádném jiném) případě musí být 2.

    Nápověda: viz příkaz tar.


  5. Vytvořte skript, který spočítá četnosti slov v textových dokumentech (může jich být libovolný počet) zadaných jako parametry skriptu. Hodnoty četností pro jednotlivá slova vypíše v pořadí určeném parametry skriptu. Skript má dva parametry -a (abecední řazení) a -r (sestupné řazení). Možná řazení výsledků jsou tedy
    • podle četnosti vzestupně (výchozí)
    • podle četnosti sestupně (parametr -r)
    • podle abecedy vzestupně (parametr -a)
    • podle abecedy sestupně (oba parametry -a -r)
    Oba parametry mohou být v libovolném pořadí, ale vždy předcházejí seznam vstupních souborů. Slovo je z pohledu skriptu sekvence abecedních znaků angličtiny, tedy a-z a A-Z (nemusíte uvažovat znaky národních abeced). Při počítání četnosti nezáleží na velikosti písmen (tedy Ahoj je totéž co ahoJ).

    Na každé řádce výstupu bude uvedeno jedno slovo a jeho četnost oddělené mezerou (v tomto pořadí).

    Pokud některý ze zadaných souborů neexistuje nebo nelze přečíst, vypíšete hlášení na chybový výstup a návratová hodnota skriptu nesmí být 0, ostatní (existující) soubory však zpracujte.

    Př.: Výstup vašeho skriptu tedy může vypadat např. takto: (spuštění s parametry -a)

    ahoj 3
    babicka 1
    doma 2

    nebo: (spuštění s parametry -r)

    ahoj 3
    doma 2
    babicka 1

    Požadavky: Společné části algoritmu vyhledávání a počítání slov by se měly ve skriptu vyskytnout jen jednou (společný kód pro všechna řazení). Nevytvářejte žádné soubory.

    Nápověda: viz příkazy sort, uniq příp. tr. Doporučujeme převést všechna slova na malá písmena. Pozor na interpunkční znaky ve vstupním textu (čárky, tečky, uvozovky apod.)

    Upozornění: řazení programem sort může záviset na nastavení proměnné LANG (popř. LC_COLLATE, LC_CTYPE) !!!


  6. Vytvořte skript, který v zadaném adresáři a jeho podadresářích najde skripty, vypíše jejich plné jméno s cestou spolu s informací, o jaký skript se jedná (shell, perl, awk, ...). Pokud není zadán adresář, prohledává se aktuální pracovní adresář. Skript má dva přepínače: nepovinný parametr -f jméno, který umožní filtrovat jen skripty zadaného jména interpretu (Pozor, zadání "-f sh" nesmí vypsat např. skripty "bash", ale jen skripty "sh") a nepovinný parametr -n (nonrecursive) který vypne prohledávání podadresářů. Pořadí argumentů může být libovolné.

    Skript poznáte podle první řádky souboru, která začíná znaky #!, pak následuje jméno programu s cestou. Pozor, za jménem interpretu mohou následovat parametry, které je třeba odříznout. Stejně tak je potřeba odříznout cestu k interpretru. Typ skriptu vypisujte jako jméno interpretu bez cesty a bez parametrů.

    Výstupem vašeho skriptu na každé řádce cesta_a_jméno_souboru a jméno_interpretru oddělené mezerou.

    Pokud zadaný adresář neexistuje, vypíšete hlášení na chybový výstup.

    Př.: Výstup vašeho skriptu může vypadat např. takto:

    /home/student/skripty/najdi.sh bash
    /home/student/skripty/bin/server.pl perl
    /home/student/skripty/bin/client.pl perl

    Nápověda: viz příkazy find a head, příp. sed.


  7. Vytvořte skript který projde zadaný tarovaný a gzipovaný archiv skupiny souborů, v každém souboru zamění zadaný textový řetězec za jiný a výsledné soubory uloží opět do stejného (původního) archivu. Parametry skriptu jsou vstupní archiv, hledané slovo a cílové slovo. Předpokládejte, že archiv obsahuje pouze textové soubory a nemá adresářovou strukturu. Žádná adresářová struktura se tedy nesmí objevit ani ve výsledném archivu.

    Výstup Vašeho skriptu, bude pouze na chybový výstup pokud zadaný archiv neexistuje, nebo se nejedná o platný tar-gzip archiv (Nerozpoznávejte podle přípony!).

    Nápověda: viz příkazy tar a sed.


  8. Sestavte skript, pro tvorbu slovníků. Vstupem skriptu bude text na stdin (nejsou-li zadány žádné vstupní soubory), nebo seznam textových souborů (může jich být libovolný počet) zadaných jako argumenty skriptu. Výstupem bude soubor, jehož jméno je určeno prvním (povinným) parametrem skriptu. Další argumenty skriptu jsou názvy vstupních souborů. Obsahem výstupního souboru budou abecedně seřazená slova (jedno slovo na řádek) vyskytující se v textu (při opakovaném výskytu se slovo ve výsledku objeví jen jednou). Slovo je z pohledu skriptu sekvence abecedních znaků angličtiny, tedy a-z a A-Z (nemusíte uvažovat slova obsahující znaky národních abeced). Pro slovník také není důležitá velikost písmen.

    Pokud některý ze zadaných souborů neexistuje, vypíšete hlášení na chybový výstup, ale zpracujte ostatní soubory a vraťte návratovou hodnotu 2. Pokud nelze přečíst žádný vstupní soubor, vraťte návratovou hodnotu 3.

    Výstupní soubor může vypadat např. takto:

    ahoj
    cau
    nazdar

    Požadavky: část kódu pro nalezení slov do slovníku bude ve skriptu jen jednou.

    Nápověda: viz příkazy sort, případně sed nebo tr. Doporučujeme převést všechna slova na malá písmena. Pozor na interpunkční znaky ve vstupním textu (čárky, tečky, uvozovky apod.)

    Upozornění: řazení programem sort může záviset na nastavení proměnné LANG (popř. LC_COLLATE, LC_CTYPE) !!!


  9. Vytvořte skript, který porovná dva adresáře (včetně podadresářů) a vypíše veškeré rozdíly, tj. jména souborů, nebo adresářů, které existují pouze v jednom adresáři, nebo mají různý čas modifikace, nebo různou délku. Dodržte formát výstupu podle příkladu: <adresář1>:<lokální-cesta> <velikost> <čas-modifikace> <adresář2>:<lokální-cesta> <velikost> <čas-modifikace> velikostje velikost souboru v bajtech a čas modifikace je čas poslední změny ve formátu "YYYY-MM-DD HH:MM". V případě neexistence souboru je vypsán jen adresář a dvojtečka.

    Jména adresářů jsou dva povinné parametry skriptu. Pokud některý ze zadaných adresářů neexistuje, nebo je nečitelný, vypíšete pouze chybové hlášení.

    Př.: Výstup vašeho skriptu, který porovnává adresáře work a archiv:

    work:a.txt 1024 2010-09-10 10:20 archiv:
    work:b.txt 20 2010-09-10 10:20 archiv:b.txt 25 2010-09-10 10:20
    work:nic.txt 100 2010-09-10 10:20 archiv:nic.txt 100 2010-09-22 15:22
    work: archiv:neco.data 256 2011-01-02 10:17
    work: adr/neco.txt 256 2012-01-05 07:30 archiv:

    Nápověda: viz příkazy find, stat, případně diff. Pozor na nadbytečné mezery ve výstupu.


  10. Vytvořte skript, který projde zadaný adresář a jeho podadresáře a vytvoří tarovaný a gzipovaný archiv všech souborů které odpovídají zadané masce. Při vytváření archivu skript dodrží adresářovou strukturu (struktura musí být relativně k zadanému adresáři - nesmí tedy obsahovat nadřazené adresáře). Skript bude mít až 4 parametry. První parametr je nepovinný přepínač -r, který povolí přepsání již existujícího archivu (pokud není zadán, nesmíte původní soubor přepsat). Další argument je procházený adresář, po něm následuje maska hledaných souborů (např. *.java, nebo A*txt*) a poslední argument definuje cestu k výslednému archívu.

    Pokud výsledný archiv již existuje a nebyl zadán přepínač -r, vypíše skript chybu na chybový výstup. Je-li zadán parametr -r a existující archiv je přepsán, vypište na chybový výstup varování. Pokud zadaný adresář neexistuje vypíše se zpráva opět na standardní chybový výstup.

    Nápověda: viz příkazy find, tar.


  11. Vytvořte skript pro vyhledání a kontrolu existence vložených souborů ve zdrojových kódech C/C++. Skript dostane jako parametry zdrojové soubory pro hledání (libovolný počet). Jménům vstupních souborů může předcházet libovolný počet parametrů ve tvaru -Icesta, které definují cesty ve kterých se hledají vložené soubory. Kromě zadaných cest hledejte soubory i ve stejné složce ve které je uložen zadaný zdrojový soubor.

    V každém zdrojovém souboru skript najde řádky #include <soubor> nebo #include "soubor". Pro každý nalezený soubor zkontrolujte jeho existenci na některé ze zadaných cest a pokud soubor nalezne vypíše plnou cestu k tomuto souboru na standardní výstup. Pokud soubor nenalezne vypíše informaci o neexistujícím souboru standardní chybový výstup (jméno souboru musí být součástí hlášení).

    Nápověda: viz příkazy grep, případně sed.


  12. Napište skript, který bude fungovat jako grep pro skupinu souborů v zadaném adresáři a podadresářích, jejichž jméno odpovídá zadané masce. Maska může mít podoby např. "*.c*", "image*", apod. Parametry skriptu jsou 3, první parametr určuje hledaný řetězec (regulární výraz), druhý parametr určuje masku souborů a třetí adresář pro rekurzivní prohledávání (pozor, téměř u všech parametrů je nutné používat ""). Třetí parametr je nepovinný, není-li zadán hledá se v aktuálním pracovním adresáři (a podadresářích).

    Těmto třem parametrům mohou předcházet přepínače: (v libovolném pořadí)
    -n ... za jménem souboru zobrazí číslo řádku ve formátu <soubor>:<č.řádku>:<nalezený-text>
    -v ... budou vypsány řádky neobsahující zadaný výraz (inverze)

    Všechna chybová hlášení, jako neexistující adresář, chybná práva pro čtení souboru budou vypsána na standardní chybový výstup.

    Př.: Výstup vašeho skriptu může vypadat např. takto: (hledaný řetězec je 'for', maska je '*.c*')

    src/test.cc:for (int i=0; i<count; i++) {
    src/common/functions.c:process_data(--number_of_samples); // decrease number before calling

    Nápověda: viz příkazy find a grep. Pokud efektivně využijete funkcí příkazu grep, značně si ulehčíte práci.


  13. Napište skript pro zvýraznění textu podle obsahu. Vstupem skriptu bude text na standardním vstupu, výstupem bude text na standardním výstupu. Liché parametry skriptu budou určovat barvu zvýraznění ('r' = červená, 'g' = zelená a 'b' = modrá) a sudé parametry hledané řetězce (regulární výrazy). Celkový počet hledaných výrazů není omezen. Nenastavujte barvu pozadí, jinak skript neprojde automatickým testem. Priorita obarvování je dána pořadím parametrů. Spuštění skriptu bez parametrů je přípustné (žádné obarvení). Zpracovávejte text po řádkách a výstup vypisujte ihned - nečekejte na konec vstupu.

    Př.:Výstup skriptu s parametry r 'bar[a-z]*\>' g 'text' b 'reg' může tedy vypadat takto:

    Napište skript pro zvýraznění textu podle obsahu.
    Vstupem skriptu bude text na standardním vstupu.
    Liché parametry skriptu budou určovat barvu zvýraznění ('r' = červená, 'g' = zelená, 'b' = modrá, alespoň tyto tři podporované barvy) a sudé parametry hledané řetězce (regulární výrazy).

  14. Nápověda: viz příkazy sed, případně echo a grep. Pro obarvení výstupu použijte sekvence typu \033[0;31;40m (viz např. zde ). Pokud budete sekvence vypisovat příkazem echo, nezapomeňte na přepínač -e.