SOP121/ćw - temat C.

Unix: powłoka "ksh"; język skryptowy.

Opis powłoki "ksh" z manuala (z drobnymi poprawkami).

Wygodne wprowadzanie komend

   powłokę "ksh" uruchamiamy poleceniem "ksh" ...

   set -o emacs
   # mozna wtedy wprowadzac i edytowac komendy w naturalny sposob
   # dziala historia polecen przy pomocy strzalek gora/dol

   set -o vi
   # niestety, w tym trybie nalezy uzywac komend edytora "vi" !
   # 2 tryby pracy :
   #     tryb komend i tryb wprowadzania znakow
   # przejscie do trybu komend : ESC
   # przejscie do trybu wprowadzania znakow : "i", "a",
   #    (lub "A" - przejscie na koniec linii !)
   # w trybie komend :
        "k" - poprzednia linia
        "j" - nastepna linia
        "h" - 1 znak w lewo
        "l" - 1 znak w prawo
        "x" - kasowanie znaku
        "/wyr_reg" - poszukiwanie tekstu (w poprzednio wprowadzo-
                     nych liniach)
        oraz wiele innych uzytecznych komend edytora "vi"
 

Jak pisać i uruchamiać skrypty

   --> ". skrypt"
       w powyzszy sposob uruchamiamy skrypt w pliku "skrypt"
       bedzie on wykonywany przez biezaca powloke !

   --> "skrypt"
       aby mozna bylo uruchamiac skrypty jak "progamy binarne"
       nalezy:
         a) w pierwszej linii umiescic nazwe interpretera, np:
              #!/bin/ksh
              # reszta skryptu ...
              ....................
         b) nadac plikowi ze skryptem prawo "x"
              chmod u+x skrypt

   UWAGA:
         polecenia, o ktorych mowa w dalszym ciagu mozna takze
         wyprobowac z linii polecen ...

 
Zadanie 33


Napisz skrypt którego interpreterem jest "cat": i uruchom go (oczywiście sposobem "z prawem x"). Wywnioskuj z tego w jaki sposób interpreter otrzymuje treść skryptu.  

Zadanie 34


Wypróbuj niektóre opisane poniżej przykłady uruchamiając je bezpośrednio w powłoce lub, w przypadku dłuższych przykładów np tego, pisząc skrypty (sposobem z prawem "x") i uruchamiając je.
Ma to na celu zrozumienie działania różnych konstrukcji powłoki ksh, tak aby można było później pisać bardziej złożone skrypty ...
Uwaga: napisy typu "if lista; then lista; fi" należy traktować symbolicznie; pod "lista" powinno się podstawić konkretną listę !.
 

Podstawowe pojęcia powłoki "ksh"

   (ten opis powloki "ksh" jest podobny do tego jaki mozna uzyskac przez "man ksh")

   *** komenda
       -> nazwa_komendy arg1 arg2 ...
            # Przykład :
              ls -l -a
              ls -ld
              cat plik.txt
              echo "1 2" 3 4
       -> rozróżniamy komendy wbudowane w powloke i
          programy (ktorych kod znajduje sie w pliku z prawem "x")
            # Przykład :
              echo 123 qqq "Q W E" # komenda wbudowana
              ls -l qqq            # program
       -> kod zakonczenia komendy :
                  0 - oznacza ok,
                  1,2,... - zazwyczaj oznacza blad
          po zakonczeniu dzialania komendy
          mozna go odczytac przez : "echo $?"
          (zmienna $? zawiera kod zakonczenia)
             # Przyklad :
               rm plik.txt; echo "kod zakonczenia=$?"
                # wyprobuj to polecenie gdy plik.txt istnieje i nie istnieje !

   *** potok
       komenda1 | komenda2 | komenda3 | ...

   *** lista
       potok1 <sep> potok2 <sep> potok3 <sep> ...
       gdzie <sep> to jeden z symboli ";" "&" "&&" "||"

       Listy są uzywane jako "cialo" oraz "warunek" w instrukcjach.

       Znaczenie symboli podwójnych ("&&" i "||") jest takie jak w języku C:
           Działanie takich list można traktować jako
           "obliczanie wartości wyrażenia logicznego z optymalizacją"
           ("&&" to koniunkcja, "||" to alternatywa).

           Kod zakończenia komend jest interpretowany logicznie:
           kod=0 to "prawda", kod<>0 to "fałsz".

           Optymalizacja polega na tym, że jeśli w czasie obliczania
           wartości wyrażenia okaże się, że wartość wyrażenia jest znana
           to nie sprawdza się pozostałych składników wyrażenia
           (nie uruchamia się ich komend !).

         # Przykłady list "logicznych":
           true && echo ABC  # wyswietla ABC
           false && echo ABC # nie wyswietla
              # true i false to komendy zwracajace kod zakonczenia 0 i 1
              #
              # w pierwszym przypadku aby poznać wartość wyrażenia
              # logicznego trzeba uruchomić drugą komendę (dlatego
              # napis ABC jest wyświetlany)
              #
              # w drugim przypadku wiadomo, że wartością tą będzie fałsz
              # dlatego komenda echo nie jest uruchamiana

           rm plik.txt && echo "Usunąlem plik !"
           rm plik.txt || echo "Nie usunąlem pliku !"
              # te przykłady działają tak jak powinny

         # Przykłady list innego rodzaju:
           ls& ls&
             # oba procesy oraz powloka dzialaja rownoczesnie !

           ls& ls;
             # pierwszy "ls" dziala jednoczesnie z drugim
             # jednak powloka czeka na zakonczenie drugiego "ls"

           ls; ls;
             # polecenia są uruchamiane po kolei
             # powłoka czeka na zakończenie każdego
             # (koncowy ";" mozna opuszczac)

   *** instrukcje sterujace
      if lista; then lista; fi

      if lista; then lista; [elif lista; then lista;] ... [else lista;] fi
        # Przykład:
        if rm plik1.txt; then echo "usunalem plik1.txt"; fi

      ... inne postacie instrukcji warunkowej
      if [[ warunek ]] then lista; fi
      if [ warunek ]; then lista; fi   # przestarzale
      if test warunek; then lista; fi  # przestarzale
             # przestarzale polecenia istnieja aby zachować zgodność z powłoką "sh"
        # Przykład:
        if [[ 1 -lt 2 ]] then echo tak; fi
        if [[ 1 -lt 2 || 2 -lt 1 ]] then echo tak; fi

     while lista; do lista; done 

  # Przykład 1: 
     i=1 
     while [[ $i -le 5 ]] 
     do 
       echo ">>>"$i"<<<"; i=$((i+1)); 
     done 
  # Przykład 2: 
     # "true" to komenda której kod zakończenia = 0 (prawda) 
     # pętla kręci się w nieskończoność ... (kończenie dzialania skryptu: Ctrl-C) 
     i=1 
     while true 
     do 
       echo ">>>"$i"<<<"; i=$((i+1)); 
     done 
  

      until list ;do list ;done

      for identifier [in word...] ;do list ;done
        # Przykład 1:
        for i in 1 2 3; do echo $i; done
        # Przykład 2:
        for i in 1 2 3
        do echo $i; done
              # dwa ostatnie przyklady sa rownowazne !!!

      select identifier [in word...] ;do list ;done
        # Przykład:
        select x in 1 2 3 4; do echo $x; done

      case word in [[(] pattern [| pattern] ...) list ;;] ...  esac
        # Przykład:
        case 5 in
          1 | 2 | 3) echo qqq;;
          4 | 5 | 6) echo www;;
          7 | 8 | 9) echo eee
        esac

      (lista)
      lista jest wykonywana w procesie potomnym (przez "ksh")
        # Przykład:
            pwd; (cd ..; pwd); pwd
               # kazdy proces ma swoj wlasny biezacy katalog
               # skoro "cd .." jest wykonywane w innym procesie
               # to nie ma wpływu na katalog bieżący naszego procesu !!!

      {lista; }
       lista jest wykonywana w procesie bieżącym
        # Przykład:
            pwd; { cd ..; pwd; }; pwd
                # ostatni ";" wewnatrz {} musi byc !
                # tutaj "cd .." jest wykonywane w naszym procesie
                # tak więc katalog bieżący się zmieni !!!
       # do czego jeszcze moga sluzyc {} ?
         # do przeadresowywanie calych grup komend :
              echo 1; echo 2 > /dev/null
              { echo 1; echo 2; } > /dev/null
                     # jaka jest różnica ?
         # w listach logicznych do grupowania komend :
               true && { echo 1; echo 2; echo 3; }
               false && { echo 1; echo 2; echo 3; }
 

      [[ warunek ]]

        W "warunku" można używać operatorów języka C:

       && - and
       || - or
       !  - not

    # Przykłady: 
       if [[ -d kat1 && -f plik.txt ]] 
            then 
              echo "kat1 jest katalogiem" 
              echo "plik.txt jest plikiem zwyklym" 
            fi 
       # "-d kat" <=> kat jest katalogiem
       # "-f plik" <=> plik jest plikiem

       if [[ 1 -lt 2 ]] then echo tak; fi 
       if [[ ! ( 1 -lt 2 ) ]] then echo tak; fi 
       if [[ 1 -lt 2 || 2 -lt 1 ]] then echo tak; fi 
       # "-lt" <=> "<"
       # "-le" <=> "<="

        Lista dostępnych operatorów (z manuala "ksh")
 

   *** substytucje (czyli podstawianie)
      -> substytucja komend
             $(lista)
          # Przyklady :
           echo "biezacy katalog to $(pwd)"
           echo "pliki TXT: $(ls -l | grep "TXT")"

      -> substytucja zmiennych
             $zmienna
             ${zmienna}
          # Przyklady :
           echo "katalog HOME to $HOME"
           echo "katalog HOME to ${HOME}abc"
           echo "biezacy katalog to $PWD"

      -> substytucja tyldy
          # Przyklady :
           echo ~user
               # wyswietla katalog HOME uzytkownika "user"
               # (pobrany z pliku /etc/passwd)

      -> jest jeszcze pare innych substytucji ...

    # Przyklady bardziej zaawansowane roznych substytucji ...
    # przypisuje zmiennej wynik działania złożonego potoku:
    prawa_do_HOME=$(ls -ld $HOME | awk '{print $1}')
    echo $prawa_do_HOME
 
    # możliwe jest także dowolne zagnieżdżanie subst. komend:
    prawa_do_kat=$(ls -ld $(pwd) | awk '{print $1}')
    echo $prawa_do_kat

    # umieszczenie w "zmiennej" zawartości pliku:
    zawartosc=$(cat plik.txt)
        # plik.txt powinien zawierac kilka linni tekstu (niektore zawierajace ABC)
        # filtrowanie zawartości (wypisuje tylko linie zawierające ABC):
    echo "przefiltrowana zawartosc : $(echo "$zawartosc" | grep 'ABC')"
        # UWAGA: w powyzszym przykladzie cudzyslowy sa wazne !; sprawdz:
    echo $zawartosc
    echo "$zawartosc"

 
   *** zmienne powłoki i środowiska
      jest wiele standardowych zmiennych
         $PATH = lista katalogów, oddzielonych ":", przeszukiwanych w czasie
                         uruchamiania programu (gdy nie podaliśmy ścieżki do pliku z programem)
         $HOME = katalog HOME użytkownika
         $0, $1, $2, ... = parametry skryptu
         $# = ilosc parametrow skryptu
         $? = kod zakonczenia ostatnie wykonywanej komendy
         $PS1, $PS2, $PS3 = prompt

      Lista dostępnych zmiennych (z manuala "ksh")

      nadawanie wartości zmiennym (lub tworzenie nowych)
      wykonuje się przy pomocy polecenia:

    zmienna1=wartość1 
          # zmienna1 jest zmienną powłoki NIE należącą do "środowiska"
	  # Przykłady:
		x1=123
		zmienna=qwe
		zmienna="qwe"
		x2="qwe asd zxc"
		   #cudzysłowy są niezbędne gdy tekst zawiera spacje

    export zmienna2=wartość2 
          # zmienna2 jest "eksportowana" czyli należy do "środowiska procesu"
	  # Przykład:
		export x1=123
      UWAGA:
         * każdy proces posiada "środowisko" zawierające zmienne
         * zmienne środowiska są dziedziczone przez procesy potomne
         * zmienne powłoki mogą należeć do "środowiska procesu" lub nie;
            zmienne tworzone poleceniem "export" należą do środowiska
         # Dwa przykłady, pokazujące różnicę między zmiennymi 
         # eksportowanymi i nieeksportowanymi : 
         x=123; ksh -c 'echo "\$x=$x"'; unset x 
         export x=123; ksh -c 'echo "\$x=$x"'; unset x

      odczytywanie wartości zmiennych (=substytucje zmiennych):

         echo $zmienna 
	 echo ${zmienna}
         echo "$zm1,$zm2" 
         echo "zm1=$zm1, zm2=$zm2" 
         echo "qqq${zmienna}www" 
           # koniecznie trzeba użyć "{}" 
         echo "${zmienna:=tekst}" 
           # opis tego wyrażenia i podobnych znajdziesz tutaj

   *** generowanie nazw plików
      echo *.txt
                 # wyswietli wszystkie pliki
                 # z biezacego katalogu o nazwie zgodnej z *.txt
                 # UWAGA: nie robi tego polecenie echo
                 #        lecz powloka (inaczej niż pod dos-em !!!)
      echo ../../*.cc
                 # wyświetl pliki *.cc z katalogu ../..
      echo abc[0-9]*.txt
                 # wyświetli pliki typu "abc1yyyyyy.txt", "abc3xxx.txt"

      Inne możliwości generowania nazw plików (z manuala "ksh")
 

   *** cytowanie
      Cytowanie to wyłączanie specjalnego znaczenia znaków
      Do cytowania służą :
              "napis"
              'napis'
              \znak

     # Co się dzieje z substytucjami podczas cytowania ???
     #
      echo *.txt , biezacy katalog $(pwd) , HOME=$HOME
      echo "*.txt , biezacy katalog $(pwd) , HOME=$HOME"
        # cudzysłowy najsłabiej cytują;
        # w ostatnim przykładzie wyłączają jednie "generowanie nazw plików"

      echo 'biezacy katalog $(pwd) , HOME=$HOME'
        # apostrofy cytują silnie;
        # wyłączają działanie wszystkich substytucji

      echo "biezacy katalog \$(pwd) , HOME=\$HOME"
      echo "biezacy katalog $(pwd) , HOME=\$HOME"
        # "\" cytuje tylko 1 znak

      # Liczba argumentow (cytowanie spacji):
      #      program "pr01.c" wyświetla swoje argumenty;
      #      spacje maja specjalne znaczenie = rozdzielanie argumentów komendy
      #
      pr01 "$HOME 2 3" # 1 argument (bo spacje sa cytowane)
                                     # jak widać, cudzysłowy działają na spację !
      pr01 $HOME 2 3   # 3 argumenty
      pr01 '$HOME 2 3' # 1 argument (bez substytucji zmiennej)
      pr01 \$HOME 2 3  # 3 argumenty (bez substytucji zmiennej)
 

   *** przeadresowywanie
      komenda >plik
      komenda >>plik
            # dopisywanie na koniec pliku
      komenda 2>plik
            # przeadresowanie "stderr" do pliku
      komenda >plik 2>&1
      komenda 1>plik 2>&1
            # przeadresowanie "stdout" do pliku oraz
            # przeadresowanie "stderr" tam gdzie przeadresowano "stdout"
            # (cyfry które tutaj występują to deskryptory: stdin-0, stdout-1, stderr-2)

      są też inne mozliwosci ...

      # Przyklad :
       cat <plik1.txt | cat | cat | cat >plik2.txt

 

   *** wyrażenia arytmetyczne
      echo "1+1=$((1+1))"
      echo "2*2=$((2*2))"
 

   *** (ważniejsze) komendy wbudowane
      . skrypt
           # (komenda ".") uruchamianie skryptu w ramach bieżącej powłoki
      set
           # wyswietla zmienne powloki
      set -o
           # wyswietla biezace opcje powloki
           # wylaczenie opcji przy pomocy "set +o"
           # Np: set +o vi

      jobs; bg; fg; # sterowanie pracami - juz omowione

      cd; pwd; # oczywiste ...

      break; # wychodzenie z roznych petli

      eval arg...; # wykonuje się substytucje; następnie
                   # argumenty są traktowane jak komenda i wykonywane
                   # (substytucje są wykonywane po raz drugi !)
        # Przykłady:
                x="echo 123"
                y='$x'
                eval $y # wykonuje sie echo 123

        # jak odczytac $i-ty parametr powloki ???
                i=10
                eval echo \${$i} # ok
                echo ${$i} # błąd !!!

      echo arg...; # wypisuje arg na stdout

      exec prog; # pojawia sie i zaczyna wykonywac nowy kod
                 # (zastepuje kod powloki !!!)

      read zmienna; # wczytuje tekst z terminala
                    # i zapisuje w zmiennej o podanej nazwie
      read zmienna?prompt;
        # Przykłady:
            read x?"Podaj nazwisko "; echo $x

      Lista komend wbudowanych w powłokę "ksh"
 
 
 

Przykłady skryptów.

Zadanie 35

Uruchom poniższe skrypty "skr??" (sposobem z prawem "x") i opisz ich działanie.

    -> przyklad skryptu, ktory czyta swoje "stdin" (linia po linii)
       i przepisuje je na "stdout" oraz "stderr": (plik "skr01");
       można się o tym przekonać dokonując odpowiednich
       przeadresowań stdout i stderr do pliku /dev/null :

            skr01 1>/dev/null
            skr01 2>/dev/null
    -> przyklad uzycia powloki "ksh" do czegos w rodzaju
       programowania wspolbieznego: (plik "skr02")

    -> skrypt analizuje swoje parametry oraz wypisuje informacje
       czy sa one nazwami plikow: (plik "skr03")
 
 

Zadanie 36


Wypróbuj opisane poniżej przykłady ("drobne" i "bardziej złożone") ...

Drobne polecenia; krótki opis.

Polecenia które warto znać:

--> basename, dirname

   # ze ścieżki do pliku "wyciąga" nazwę pliku (bez sufiksu ".gz"):
   basename /qqq/www/plik.txt.gz .gz
   plik.txt

   # ... to samo co wyżej;
   # dodatkowo umieszcza nazwę pliku w zmiennej
   nazwa_pliku=$(basename /qqq/www/plik.txt.gz .gz)
--> grep, less, more, env  
 

Polecenia bardziej złożone; krótki opis.

*** expr ***

Polecenie "expr" sluzy do obliczania wartosci wyrazen.

Warto pamietac ze powloka ksh ma wbudowana konstrukcje
do obliczania wartosci wyrazen arytmetycznych:
   echo $((2*2))
   4

Polecenie expr pozwala robic podobne rzeczy:
   expr 1 + 1
   2
   expr 2 \* 2 # ??? dlaczego \* a nie * ???
   4
Zwroc uwage, ze skladniki wyrazenia musza byc
osobnymi parametrami polecenia !.

Jednak polecnie expr ma wieksze mozliwosci niz $(()):
   expr "qqqqwww" : "qq*"; echo $?
   4
   0
   expr "qqqqwww" : "qq*$"; echo $?
   0
   1
W powyzszym przykladzie sprawdza sie czy string "qqqwww"
pasuje do wyrazenia regularnego "qq*" oraz do "qq*$"
Polecenie wyswietla ilosc znakow pasujacych do wyrazenia.
Kod wyjscia (dostepny poprzez zmienna "?") jest ustawiany
na 0 gdy string pasuje do wyrazenia, na 1 gdy nie pasuje.

Przykladowo "qq*" oznacza string zaczynajacy sie od "q",
po ktorym nastepuje dowolna ilosc literek "q" (byc moze rowna 0).
Wyrazenie "qq*$" oznacza ciagi literek "q" zawierajace
przynajmniej jedna literke.
 

*** find ***

find katalog wyrażenie_logiczne

Jest to polecenie do wykonywania pewnych czynności na całym drzewie katalogów.

Przebiega się wszystkie pliki i katalogi wychodzące z katalog, i dla każdego pliku/katalogu
oblicza się wyrażenie_logiczne ...

Składnik "-print" wyrażenia logicznego powoduje wypisanie nazwy bieżącego pliku/katalogu,
co można wykorzystać następująco:

  find /usr/bin \( -name '*.c' -o -name '*.cc' \) -print
    # wyświetla wszystkie pliki w katalogach wychodzących z /usr/bin
    # które maja nazwę zgodna ze wzorcem *.c LUB *.cc
    # -o <=> OR (=LUB), -a <=> AND (=I)
    # Uwaga: w składnikach pierwszego poziomu wyrażenia logicznego
    #   nie trzeba używać -a (i tak są traktowane jak koniunkcja)
Dlaczego powyższy przykład działa jak opisałem ?
Odp: gdyż wartość wyrażenia logicznego jest obliczana "z optymalizacja";
składniki "pierwszego poziomu" czyli:
    \( -name '*.c' -o -name '*.cc' \)
oraz
    -print
są traktowane jako koniunkcja (-a, AND); jeśli pierwszy składnik zwraca fałsz,
to drugiego już się nie oblicza (bo wiadomo że wartością wyrażenia jest fałsz).

inny przykład :

  find /usr/bin -type d -exec ls -ld {} \;
    # dla wszystkich plików typu katalog (-type d) wykonuje się
    # polecenie ls -ld "katalog"
 

*** awk ***

UWAGA: To jest jedynie skrócony opis polecenia "awk"

Dokumentacja w j. ang jest w plikach "awk.txt" oraz "awk2.txt";
jest takze dostepny opis po polsku "Kilka faktów o awk".

Program "awk" jest to proste narzędzie do przetwarzania tekstu.
W Unix-ie jest używany do "wyciągania" informacji z wyjścia
różnych poleceń takich jak "ls" i "ps".

Program "awk" czyta tekst ze standardowego wejścia.
Tekst ten jest traktowany jak ciąg rekordów
       (którymi standardowo są linie tekstu).
Rekordy dzielą się na pola
       (standardowym separatorem pól jest spacja).
Dostęp do pól rekordu:
        $0 - cały rekord,
        $1 - pierwsze pole,
        $2 - drugie pole,
        ..........................
        ..........................
Innymi słowy rekordy to "linie tekstu", a pola to "słowa w liniach".  

Skrypt programu "awk" zawiera pary:
   Wzorzec1 { Czynnosc1 }
   Wzorzec2 { Czynnosc2 }
   ......................................
   ......................................
gdzie "Wzorzec" jest /wyrażeniem regularnym/ lub wyrażeniem logicznym języka C,
natomiast "Czynność" jest kodem zapisanym w języku podobnym do C.
"Czynność" polega zazwyczaj na wypisaniu pewnych informacji.
 
Rekordy są przeglądane kolejno.
Jeśli pewien rekord jest zgodny ze "Wzorcem",
to jest wykonywana "Czynność".

Istnieja "Wzorce" specjalne BEGIN i END zgodne z pierwszym i ostatnim rekordem.

Przyklady:
     ls -l | awk '{print $1 " " $9}'
     # wypisuje tylko prawa i nazwy plikow ("pola" o nr 1 i 9).
     # w tym przykładzie "wzorzec" jest pusty <=> wszystkie rekordy są z nim zgodne

     ls -l | awk '$2>10{print $0}'
     # wypisuje tylko te pliki które mają "liczbę dowiązań" > 10.

     ps -o pid,ppid  |  awk '$2==1234 {print $1}'
     # wypisuje PID-y procesów z PPID=1234

     awk 'BEGIN     {s=0};
             /^[0-9]+$/ {s=s+$1};
             END         {print "suma liczb calkowitych = " s}'
     # dodaje wszystkie linie ktore
     # zawieraja tylko i wylacznie liczbe calkowita

     awk '         {tablica[$1]=tablica[$1]","$2};
             END {for (x in tablica) {print x " " tablica[x]}}'
     # jeśli na wejściu dostanie:
          1 a
          1 b
          x q
          2 a
          1 c
          2 b
          x w
          x e
     # to zwróci wynik:
          1,a,b,c
          2,a,b
          x,q,w,e
 
 

Wyrażenia regularne:

   The ^ matches the beginning of the string.

   The $ matches the end of the string.

   A \ followed by a single character matches that character (???)

   A . matches any character.

   A single character with no special meaning matches that character.

   A string enclosed in brackets [] matches any single character in that string.
   Ranges of ASCII character codes may be abbreviated as 'a-z0-9'.
   A left bracket ] may occur only as the first character of the string.
   A literal - must be placed where it can't be mistaken as a range indicator.
   If the first character is the caret ^ then any character not in the
   string will match.

   A regular expression followed by * matches a sequence of 0 or more
   matches of the regular expression.

   A regular expression followed by + matches a sequence of 1 or more
   matches of the regular expression.

   A regular expression followed by ? matches a sequence of 0 or 1
   matches of the regular expression.

   Two adjacent (concatenated) regular expressions match a match of the first
   followed by a match of the second.

   Two regular expressions separated by | match either a match for the
   first or a match for the second.

   A regular expression enclosed in parentheses matches a match for the
   regular expression.

   The order of precedence of operators at the same parenthesis level is
   [] then *+? then concatenation then |.
 
 

 

Zadania skryptowe.

Zadanie S1

   Napisz skrypt wyswietlajacy swoje parametry niezaleznie od ich liczby,
   która może być > 10; patrz zmienna $#.

Zadanie S2

   Napisz skrypt ktory uruchamia edytor (np "pico" lub "vi")
   dla podanego pliku. Jesli plik jest skompresowany
   to zostanie "odkompresowany" w tym katalogu w ktorym
   istnieje lub - o ile to niemozliwe - w katalogu HOME.
   Po wyjsciu z edytora plik jest kompresowany (aby przywrocic pierwotna sytuacje).
   Kompresowanie pliku:
       gzip plik.txt
       # nastepuje zmiana nazwy pliku na "plik.txt.gz"
   Dekompresowanie pliku:
       gzip -d plik.txt.gz
       # nastepuje zmiana nazwy pliku na"plik.txt"

Zadanie S3

   Napisz skrypt "prawa" pokazujacy prawa do wszystkich
   katalogow w scieżce do pliku podanej jako parametr;
   wykorzystaj polecenia "cd ..", "ls -ld", "awk", ...

Zadanie S4

   Napisz skrypt (z uzyciem "awk"), ktory wysyla podany sygnal
   do BEZPOSREDNICH potomkow danego procesu;
   wywolanie:
       sygnal1 -kill 1234
           # wysyła SIGKILL do bezpośrednich potomków procesu z PID=1234


Zadanie S5

   Napisz skrypt "kopiuj_jesli_trzeba", który uruchamia
   się podając jako parametry dwa katalogi: kat1 i kat2.
   Skrypt porównuje zawartość obu katalogów i kopiuje
   pliki z kat1 do kat2 jeśli w kat2 nie ma danego pliku
   lub plik w kat2 jest starszy.
   Skrypt powinien wyswietlać informacje o tym co robi.

Zadanie S6

   Napisz dwa skrypty: "sleep1" i "sleep2".  Pierwszy z nich tworzy 3 procesy drugoplanowe:
      sleep 121 &  sleep 122 &  sleep 123 &
   Natomiast drugi zabija je.

Zadanie S7

   Napisz przykladowy skrypt, ktory tworzy 2 procesy potomne
   komunikujace sie przy pomocy lacza nazwanego, uzyj "()", "&", "<", ">".
   Jeden z procesow powinien wysylac komunikaty a drugi je odbierac.
   Oba procesy powinny wyswietlac na terminalu informacje o tym co robia.
   Ma to byc cos podobnego do przykladu "skr02".

Zadanie S8

   Napisz skrypt "nc" pozwalajacy chodzic po
   drzewie katalogow, wykonywac programy,
   ogladac zawartosc plikow, itp.
   wykorzystaj polecenie "select" do wyswietlania listy plikow,

Zadanie S9

   Napisz skrypt "nowi" wyswietlajacy wszystkich
   nowych uzytkownikow (musi tam byc proces dzialajacy w tle !);
   wykorzystaj polecenia:
        who # wyswietla zalogowanych uzytkownikow,
        diff # porownuje zawartosc 2 plikow

Zadanie S10

   Napisz skrypt "prawa3" nadajacy katalogom w sciezce do podanego
   pliku podane prawo.
      Np: prawa3  g=x  /aaa/bbb/ccc/plik.txt
          # nada prawa :
          #   chmod g=x /aaa/bbb/ccc
          #   chmod g=x /aaa/bbb
          #   chmod g=x /aaa
          #   chmod g=x /

Zadanie S11

  Napisz skrypt (z użyciem "awk"), który wysyła podany sygnał do wszystkich
  potomkow danego procesu, takze tych NIE BEZPOŚREDNICH !
  Uruchamianie:
     sygnal2 -kill 1234
  UWAGA: to wymaga wyrafinowanego użycia "awk"; (przeanalizuj przyklad "awk01")
  Opisz także jak działa "awk01" !

Zadanie S12

  Napisz skrypt "wymiana_naglowkow", ktory uruchamia sie
  nastepujaco:
     wymiana_naglowkow naglowek.txt plik1.txt plik2.txt ...
  Skrypt ten powinien ZAMIENIC naglowki plikow "plik?.txt"
  na zawartosc pliku "naglowek.txt".
  Ile poczatkowych linii tekst uwaza sie za naglowek pliku
  zalezy od ilosci linii pliku "naglowek.txt" (mozna ja
  odczytac poleceniem "wc -l naglowek.txt").
  Inne przydatne polecenia: "head" i "tail".  

Zadanie S13

  Napisz skrypt ktory powiadamia uzytkownika
  gdy pewna osoba sie zaloguje do maszyny X:
     powiadom_mnie jkowalski
  wyswietlajac odpwiednie napisy na terminalu
  (skrypt powinien uruchamiac proces dzialajacy w tle)
  Przydatne polecenia: "finger"/"who", "sleep"

Zadanie S14

  Napisz skrypt, ktory tworzy plik "manual1.tty",
  zawierajacy strony manuala dla pierwszych 10 polecen z katalogu "/usr/bin",
  ktorych nazwy zaczynaja sie od malej litery;
  kazda strona ma byc poprzedzona naglowkiem postaci:
    --- polecenie ---
  Przydatne polecenia: "grep"+wyr.reg., "head"

Zadanie S15

  Napisz skrypt ktory dostaje w linii parametrow
  nazwy polecen :   a następnie tworzy pliki "ascii" o nazwach   zawierajace tresc manuala BEZ kodow przeznaczonych dla
  terminala (trzeba "odfiltrowac" pewne znaki).
  Mozna to zrobic przy pomocy programu "sed".
  Program sed pozwala zastępować tekst1 (który może być wyr. reg.)
  przez tekst2 następująco:
    sed -e 's/tekst1/tekst2/g'
  Pytanie: jak wprowadzać znaki typu ^A, ^B, ^H (o kodach 1, 2, 8) ?
  Odp: w bash-u, w edytorze vi, w powłoce ksh po uruchomieniu "set -o vi"
  można to zrobić poprzez Ctrl-v + Ctrl-literka

Zadanie S16
  Napisz skrypt ktory wyświetla informacje (krótkie opisy) o zainstalowanych pakietach RPM dotyczących języka PHP
  (przydatne    polecenia: rpm, rpm -qa, rpm -qi pakiet, zajrzyj do manuala !)

Zadanie S17
  Wymyśl własne zastosowanie skryptu (problem jaki można wygodnie rozwiązać przy pomocy skryptu i poznanych narzędzi).

Zadanie S18
  Napisz skrypt wyświetlający drzewo katalogów w postaci pseudo-graficznej (jak DOSowy program Tree).

Zadanie S19
  Napisz skrypt który otrzymuje przez parametr nazwę pliku, a następnie
  wypisuje jego zawartość na stdout numerując kolejne linie; powinno to wyglądać tak:
(1) qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq
(2) wwwwwwwwwwwwwwwwwwwwwww
.....................
.....................
  Uwaga do zadania S19: plik nie powinien być przekazany do skryptu
  przez stdin, tylko jego nazwa jest podawana przez parametr skryptu !

Zadanie S20
  Napisz skrypt który otrzymuje przez parametry nazwy dwóch plików,
  czyta z nich po jednej linii (w pętli, aż do skończenia jednego z plików),
  łączy te linie i wypisuje na stdout.
  Jeśli pliki wejściowe nie mają równej liczby linii to skrypt
  wypisuje pozostałe w jednym z plików linie na końcu.