bash

Materiały

Powłoka systemu Unix

Powłoka (shell) była swego czasu jedynym sposobem komunikacji z systemem Unix czy z systemami uniksopodobnymi (jak Linux). Mimo, że większośc użytkowników komputerów korzysta dzisiaj z interfejsu graficznego, interfejs tekstowy pozwala wykonywać powtarzalne zadania szybciej i bardziej niezawodnie, dlatego warto go dobrze poznać. Od połowy 2016. roku uniksową powłokę można używać także na systemie Windows 10.

Zadaniem powłoki jest wyświetlać wiersz poleceń, przyjmować polecenia wpisywane z klawiatury przez użytkownika, znajdować i uruchamiać żądane programy. Z biegiem czasu powłoka stała się kompletnym, choć dość specyficznym językiem programowania i służy też do pisania skryptów (czyli programów interpretowanych wprost przez powłokę). Powłoka udostępnia zmienne, pętle, instrukcje warunkowe itp.

W historii powstało kilka różnych programów powłoki:

bash

Będziemy zajmować się najbardziej popularną powłoką bash.

Po włączeniu powłoki (albo w oknie emulatora terminala albo po zalogowaniu w wirtualnej konsoli), pierwsza rzecz jaką zobaczymy to znak zachęty (ang. command prompt) sygnalizujący gotowość powłoki do przyjmowania poleceń. Jeżeli mamy do czynienia ze zwykłym użytkownikiem, znak zachęty to (standardowo) $, jeżeli użytkownik jest administratorem (czyli rootem), to znak zachęty to #. Znak zachęty standardowo piszemy, ponieważ sygnalizuje on, że mamy do czynienia z poleceniem powłoki, poza tym sygnalizuje ewentualną koniecznośc wykonania z prawami administratora.

Wpisywane do powłoki polecenia mają następującą strukturę:

$ polecenie argument1 argument2 argument3 ..

Wpisane polecenie może być tzw. poleceniem wbudowanym powłoki (czyli jest wykonywane przez powłokę). Jeżeli polecenie nie jest poleceniem wbudowanym, to powłoka szuka programu o nazwie polecenie w katalogach znajdująch sie w tzw. ścieżce (W systemach uniksowych pliki wykonywalne najczęściej nie mają rozszerzeń). Jeżeli taki program zostanie znaleziony, to jest wykonywany z podanymi argumentami, jeżeli nie zostanie znaleziony, to zostanie wyświetlony błąd. Programy nie znajdujące się na ścieżce można wywoływać podając ich scieżkę bezwględną lub względną.

Systemy Uniksowe rozróżniają wielkość znaków. Plik, plik, PLIK i pLiK mogą istnieć w tym samym katalogu i mieć różną zawartość. Polecenie i polecenie to nie to samo. w nazwach poleceń i programów najczęściej używamy tylko małych liter.

Każdy program uniksowy ma stowarzyszone tzw. standardowe wejście i standardowe wyjście. Normalnie standardowe wejście jest przypisane do klawiatury, a standardowe wyjście jest wypisywane na ekranie, ale powłoka pozwala łatwo łączyć wejście jednego programu z wyjściem następnego czy też przekierowywać je z/do plików. O tych mechanizmach jednak za chwilę.

Najważniejsze polecenia i programy

  • Polecenia wbudowane:
    • source – powoduje wczytanie podanego pliku, potraktowanie kolejnych linii jako poleceń i wykonanie w obecnej powłoce
    • alias – pozwala ustawiać sróty dla często wywoływanych poleceń
    • cd – zmienia bieżący katalog
    • echo – wypisz podane argumenty na stadardowe wyjście
    • help – wyświetla krótką pomoc dotyczącą poleceń wbudowanych
    • history – wyświetla historię wpisywanych poleceń
    • pwd – wyświetla obecny katalog bieżący
    • pushd [katalog] – odkłada biężący katalog na stos katalogów i zmienia bieżący katalog na podany katalog
    • popd – zmienia katalog bieżący na katalog znajdujący się na szczycie stosu katalogów i zdejmuje jeden element ze stosu katalogów
    • test lub [ – pozwala sprawdzać warunki (głównie na potrzeby pętli i instrukcji warunkowej)
  • Programy zewnętrzne:
    • Pakiet coreutils (małe, podstawowe programy):
      • programy działające na całych plikach
        • chmod – zmienia uprawnienia podanych plików
        • chown – zmienia właściciela podanych plików
        • cp – kopiuje żródło do celu, parametrów może być więcej, wtedy ostani musi być katalogiem
        • dir oraz ls – wypisuje zawartośc katalogu, programy różnią się tylko domyślnym sposobem prezentacji wyników
        • ln – tworzy łącza twarde i łącza symboliczne (coś w rodzaju wskaźników na pliki i katalogi)
        • md5sum, sha1sum, ... – oblicza sumy kontrolne podanych plików
        • mkdir – tworzenie katalogów
        • mv – zmienia nazwy plików i katalogów
        • rm, rmdir – usuwanie plików i katalogów
        • shred – bezpiecznie usuwa pliki, zamazując najpierw ich zawartość dla bezpieczeństwa, w praktyce na nowoczesnych systemach plików często bezużyteczny
        • split – dzielenie plików na równe, mniejsze części
        • stat – wyświetlanie informacji o plikach
        • touch – towrzy puste pliki, zmienia czas ostatniego dostępu dla plików istniejących
      • Programy działające na zawartości plików (głównie tekstowych)
        • cat – kopiuje standardowe wejście na wyjście
        • cut – pozwala wycinać z każdej linijki tekstu interesujące nas dane (np. trzecie słowo)
        • head, tail – wypiywanie początku bądź końca pliku (standardowo 10 linijek)
        • nl – numerowanie linii wejścia
        • sort – sortuje linijki tekstu
        • shuf – miesza linijki tekstu
        • uniq – wypisuje niepowtarzające sie linijki wcześniej posortowanego tekstu
        • od – wypisuje zawartość plików i strumieni binarnych
        • wc – wypisuje liczbę linii, słów i znaków
      • Pozostałe
        • sleep – nic nie robi przez podaną liczbę sekund (przydatne czasem w skryptach i pętlach)
        • date – wypisuje aktualny czas
        • kill – wysyła sygnały do procesów, pozwalając zabić zawieszony program itp.
    • Inne przydatne narzędzia
      • Informacje i pomoc
        • man – starszy system dokumentacji, każde polecenie opisane na jednej długiej stronie (o ile autor dołożył wysiłku w stworzenie takiej dokumentacji)
        • info – nowszy system, pozwala dzielić dokumentację na strony razem z nawigacją, efektem jest coś w rodzaju książki z rodziałami
      • Wyszukiwanie informacji
        • grep – wypisuje linijki tekstu pasujące do podanego wyrażenia regularnego lub wyszukuje wyrażeń regularnych w plikach
        • find – wyszukuje pliki spełniające podane kryteria
      • Edycja plików
        • sed – edytor strumieniowy, pozwala na wykonywanie tej samej operacji znajdź/zamień na wielu liniach tekstu (w istocie kompletny, ale dość skomplikowany język programowania)
        • awk – język programowania do przetwarzania tekstu (bardziej przejrzysty niż sed)
        • nano – prosty edytor tekstu
        • emacs i vim – dwa najbardziej popularne edytory tekstu dla programistów
      • Kompresja i archiwizacja
        • tar – łączy wiele plików w jeden bez kompresji (archiwizacja)
        • gzip, bzip2, xz – strumieniowa kompresja danych (często łączymy pliki w jeden tar-em i kompresujemy jednym z tych programów)
      • Sieć
        • ncnetcat, zestawianie prostych połączeń sieciowych itp.
        • nmap – narzędzie do testowania sieci, testów penetracyjnych, skanowania portów itp.
        • ssh – bezpieczne połączenia ze zdalnymi maszynami protokołem SSH
        • rsync – możliwie szybkie kopiowanie plików między różnymi maszynami (rsync zauważy, że plik już istnieje, albo trzeba tylko ostatnie parę bajtów przesłać itp.)
        • wget – pobieranie plików
        • ip – konfiguracja sieci
        • iw – konfiguracja sieci wifi
      • Inne
        • less – pozwala oglądać dłuższe pliki po jednym ekranie naraz
        • diff – wyszukiwanie różnic między plikami tekstowymi (np. dwie wersje tego samego programu)
        • ps, top – informacje o działających programach
        • make – narzędzie do tworzenia plików z istniejących plików poprzez zadane reguły (najczęściej wykorzystywane przy kompilacji programów)
        • parted – narzędzie do zarządzania partycjami, formatowania partycji itp.
        • gcc, g++ – kompilatory C i C++ z projektu GNU
        • clang, clang++ – kompilatory C i C++ z projektu LLVM
        • gdb – debugger

Argumenty poleceń i programów

Argumenty linii poleceń są obsługiwane przez wywoływany program, więc nie ma jednej reguły jak zostaną potraktowane. Z biegiem czasu wykształciły sie jednak pewne konwencje.

  • Jeżeli argument nie jest poprzedzony znakiem - i nie jest wartością jakiejś opcji, to jest najczęściej traktowany jako nazwa pliku. W zależności od programu plik będzie np. usunięty (rm) albo jego zawartość zostanie wczytana na standardowe wejście programu (np. cat, sort). Jeżeli plików jest więcej będą wczytane/usunięte kolejno. Argumenty obowiązkowe również będą często wpisywane bez poprzedzania ich żadnym innym znakiem czy przełącznikiem, dla wygody. Wtedy kolejność decyduje o znaczeniu danego argumentu.
  • Jeżeli argument zaczyna się od -, to jest tzw. krótkim przełącznikiem, najczęściej w postaci jednej litery. Niektóre przełączniki wymagają argumentu (np. ssh -p 23 powoduje łączenie się z portem 23), niektóre ich nie wymagają (np. ls -l wypisuje zawartośc katalogu ze szczegółami). Przełączniki bez argumentów często można łączyć ze sobą (np. ls -lR to to samo co ls -l -R).
  • Jeżeli argument zaczyna się od --, to jest długim przełącznikiem, najczęściej w postaci słowa bądź słów połączonych łącznikami. Może wymagać argumentu lub nie. Często są to po prostu inne sposoby wywoływania krótkich przełączników (może raczej: krótkie są skrótami tych długich). Przełączników długich nie można łączyć ze sobą, choć może ich być więcej niż jeden (np. ls --all --recursive, równoważnie ls -aR).
  • Szybka pomoc jest często wyświetlana po wywołaniu polecenia z argumentem -h lub --help.
  • Przełączniki z reguły występują przed argumentami będącymi nazwami plików.

Niektóre polecenia mają bardziej skomplikowane sposoby wywoływania i dużo opcji. Programiści często umieszczają opis w plikach man lub info. Można spróbować:

$ man polecnie
$ info polecenie

W obu programach pomoc ich dotyczącą (nawigacja, wyszukiwanie itp.) wyświetlamy klawiszem H i zamykamy klawiszem q.

Dokumentację zamykamy klawiszem q.

Spacje w argumentach

Powłoka normalnie przyjmuje, że spacja rozdziela argumenty. Znaczy to, że poniższe polecenie:

$ rmdir Moje dokumenty

Zamiast usunąc katalog Moje dokumenty zostanie błędnie zinterpretowane jako polecenie usunięcia dwóch katalogów: Moje i dokumenty. Aby powstrzymać powłokę od normalnego traktowania spacji można poprzedzić ją znakiem \ lub wziąć cały napis w cudzysłów (pojedynczy lub podwójny). Poniższe poleceni robią to co trzeba:

$ rmdir Moje\ dokumenty
$ rmdir "Moje dokumenty"
$ rmdir 'Moje dokumenty'

Globbing

Jedną z głównych przewag powłoki jest wygodna praca z wieloma plikami jednocześnie. W prostych przypadkach pomaga globbing czyli rozwijanie szablonów nazw plików. Jeżeli powłoka w argumencie znajdzie znak * lub ? to traktuje go jako szablon nazw plików i podmnienia ten argument na listę wszystkich nazw plików iw bieżącym katalogu pasujących do szablonu, gdzie znak * zastępuje dowolny ciąg znaków (także pusty) a znak ? zastępuje jedną literę. Samotny znak * oznacza wszystkie pliki. Dla przykładu:

$ touch a aa b bb cc

$ ls
a
aa
b
bb
c
cc

$ ls a*
a
aa

$ ls b?
bb

$ ls ??
aa
bb
cc

$ rm *
$ ls

Powyższy mechanizm jest obsługiwany przez samą powłokę, polecenia nie dostają w swoich argumentach znaku * tylko rozwiniętą, porozdzielaną spacjami listę plików. Spacje w nazwach plików mogą powodować różne problemy (z którymi można i trzeba sobie radzić, ale to za dużo na wstępne zajęcia).

Potoki i przekierowania

Potoki

Powyższe narzędzia potrafią być bardzo użyteczne same w sobie. Jenak idea przyświecająca autorom wielu Uniksowych rozwiązań każe robić jedną rzecz i robić ją dobrze. Stąd wiele powyższych programów nie jest kombajnami (chociaż nmap i wget prawdopodobnie można by tak nazwać). Jednym z elementów filozofii Uniksa jest tworzenie z małych programów większych poleceń potrafiących wykonać bardziej skomplikowane zadania, podobnie jak rzemieślnik używa najczęściej wielu stosunkowo prostych narzędzi aby wykonać często nie taką prostą pracę.

Do łączenia poleceń służy tzw. potok (ang. pipe). Potok łączy dwa polecenia w taki sposób, że wyjście jednego jest wejściem kolejnego, tyma samym efekt pracy jednego z programów może być dalej zmieniany przez kolejny program. potok zapisujemy z użyciem pionowej kreski (|).

Dla przykładu poniższe polecenie znajduje najczęściej występujące wyrazy w drugiej kolumnie pliku file.txt:

$ cut -f2 file.txt | sort | uniq -c | sort -k1nr | head

Kolejne polecenia:

  • cut -f2 file.txt – wczytuje kolejne linijki pliku tekstowego i wysyła na wyjście tylko drugą kolumnę z każdego wiersza (kolumny oddzielone znakami tabulacji)
  • sort – sortuje alfabetycznie, wielokrotnie występujące linie się powtarzają
  • uniq -c – wielokrotnie występujące linie są usuwane, na początku każdej linii zapisywane jest ile razy występowała
  • sort -k1nr – sortuje po pierwszym elemencie każdego wiersza, który ma być traktowany jako liczba i sortowany malejąco
  • head – wyświetla tylko początek listy słów

Przekierowania

Czasem chcemy, żeby wejście do polecenia nie było z klawiatury, lecz z pliku. Podobnie możemy chcieć, aby wynik nie był wypisywany na ekran lecz zapisywany do pliku. Służą do tego przekierowania:

  • polecenie <plik – wejściem do polecenia będzie zawartość pliku, tzn. polecenie zachowa się tak jak gdybyśmy wpisali zawartośc pliku z klawiatury (łącznie ze znakami nowej linii itp.)
  • polecenie >plik – wyjście z programu zostanie zapisane do pliku, zawartość zostanie zastąpiona
  • polecenie >>plik – wyjście z programu zostanie dopisane na końcu pliku

Przydatne skróty

  • Ctrl+R – rozpocznij wyszykiwanie w historii poleceń
  • Ctrl+D – wyślij znak końca pliku
  • Ctrl+C – wyślij do bieżącego procesu sygnał SIGINT, w praktyce najczęściej przerywa jego działanie
  • Ctrl+Z – wyślij do bieżacego procesu sygnał SIGTSTP, który najczęściej zatrzymuje ten proces; proces można ponownie uruchomić poleceniem fg

Podstawowe polecenia – operacje na plikach

Podstawowe operacje plikowe wraz ze składnią i najważniejszymi przełącznikami:

  • touch [plik1] [plik2] ... – ustawia czas ostatniego dostępu podanych plików na czas wykonania polecenia, jeśli podany plik nie istnieje, zostanie utworzony pusty plik o tej nazwie
  • rm [plik1] [plik2] ... – usuwa podane pliki (nie będące katalogami)
    • -d – usuwa także puste katalogi
    • -r – usuwa pliki i katalogi rekurencyjnie
    • -f – wymusza usunięcie plików, nigdy o nic nie pyta
  • rmdir [katalog1] [katalog2] ... – usuwa podane katalogi, o ile są puste
  • cp [plik1] [plik2] – kopiuje zawartość pliku1 do pliku2, jeżeli plik2 istnieje, zostanie nadpisany, jeżeli plik2 istnieje i jest katalogiem, to plik1 będzie skopiowany do tego katalogu, lista może zawierać więcej niż dwa pliki, ale wtedy ostatni musi być katalogiem
    • -r – kopiuje katalogi rekurencyjnie
    • -n – nie nadpisuje istniejących plików
  • mv [plik1] [plik2] – przenosi plik1 do plik2, jeżeli plik2 istnieje, zostanie nadpisany, jeżeli plik2 istnieje i jest katalogiem, to plik1 będzie przeniesiony do tego katalogu, lista może zawierać więcej niż dwa pliki, ale wtedy ostatni musi być katalogiem
    • -n – nie nadpisuje istniejących plików
  • cd [katalog] – wbudowane polecenie powłoki, zmieniające bieżący katalog na podany, w każdym katalogu istnieje „magiczny” katalog .., wskazujący na katalog nadrzędny
  • ls [katalog] – wypisuje zawartość podanego katalogu (lub katalogu bieżącego w przypadku barku paramatrów)
    • -l – wypisuje ze szczegółami
    • -R – wypisuje zawartośc napotkanych katalogów rekurencyjnie
    • -a – wyświetla także pliki ukryte (czyli o nazwach zaczynających się od kropki)

Przykład na zajęcia. Wykonaj w konsoli kolejno następujące polecenia. Polecenia te pokazują najprostsze operacje na plikach. Wskazówka: strzałaka w górę pozwala przywołać z pamięci poprzednie polecenia, które można edytować i wykonać. Linijki poprzedzone znakiem # to komentarze.

# Tworzenie nowego katalogu.
# W katalogu /dev/shm normalnie montowany jest ramdysk,
# wszystkie wykonane operacje znikną po wyłączeniu komputera
mkdir /dev/shm/katalog

# Zmiana katalogu bieżącego:
cd /dev/shm/katalog

# Linuksowe systemy plików rozróżniają wielkość znaków!
mkdir dir_a DIR_A DiR_A dIr_a dir_b dir_c

# Wylistowanie zawartości katalogu bieżącego:
ls

# Usuwanie wskazaynch pustych katalogów:
rmdir DIR_A DiR_A dIr_a

# Wylistowanie ze szczegółami:
ls -l

# Tworzenie pustych plików:
touch a b c

# Kopiowanie pliku do katalogu i pliku do innego pliku:
cp a dir_a
cp a d

# kopiowanie katalogu wraz z zawartością i opisem wykonywanych operacji:
cp -Rv dir_a dir_c

# Wylistowanie rekurencyjne
ls -R

# Przenoszenie plików do katalogu i zmiana nazwy pliku:
mv d dir_a
mv dir_c dir_a
mv b e

ls -R

# Tworzymy 100 plików w pętli:
for i in `seq -w 1 100`; do touch $i.txt; done

ls -R

# Operacje na wielu plikach naraz:
mv 01*txt dir_a
cp *9.txt dir_b

ls -R

# Usunięcie wskazanego katalogu wraz z zawartością:
rm -r dir_a

ls -r

# Usunięcie wszystkich plików z bieżącego katalogu:
rm -rf *

W praktyce używanie tych poleceń mogłoby wyglądać tak:

Kompilator w linii poleceń

Poniższy program używa interfejsu C++ biblioteki GMP i pozwala na mnożenie dowolnie dużych liczb (ograniczeniem jest tylko dostępna pamięć):

#include <iostream>
#include <gmpxx.h>

int main(int argc, char *argv[]) {
    if (argc >= 3) {
        mpz_class a(argv[1]), b(argv[2]);
        std::cout << a*b << std::endl;
    }
    return 0;
}

Po zapisaniu kodu programu jako plik gmp.cpp, możemy go skompilować i skonsolidować kompilatorem g++:

$ g++ gmp.cpp -o gmp -lgmp -lgmpxx

Kompilator powinien utworzyć plik wykonywalny gmp w bieżącym katalogu. Flagi -lgmp i -lgmpxx są konieczne, aby konsolidator znalazł potrzebne biblioteki (jeżeli piszemy własny program, nie używający GMP, to nie potrzebujemy tych flag). Aby uruchomić nasz program wpisujemy na przykład:

$ ./gmp 111111111111111111111111111111111111111111111111111111 2

Bieżący katalog z reguły nie znajduje się w ścieżce przeszukiwania dla wywoływanych poleceń. Znaki ./ wymuszają przeszukanie bieżącego katalogu.

Powyższe polecenie równocześnie skompilowało i skonsolidowało nasz program. Możemy zrobić to w dwóch krokach, bywa to przydatne przy większych projektach – mała zmiana w jednym pliku źródłowym nie wymaga wtedy przekompilowywania całego projektu, więc cały proces zajmuje mniej czasu. Aby rozdzielić kompilację i konsolidację używamy przełącznika -c:

$ g++ gmp.cpp -c -o gmp.o
$ g++ gmp.o -o gmp -lgmp -lgmpxx

Zauważmy, że kompilacja powiedzie się bez bibliotek, dopiero konsolidacja wymaga podania odpowiednich flag.

Kompilator w rodzaju g++ pozwala na podanie tysięcy różnych opcji wpływających na proces kompilacji (poziom optymalizacji, model i architektura procesora itd.). Wszystkie opcje znajdziemy w podręczniku: info g++.

Program make

Sensownej wielkości programy są kompilowane setki czy tysiące razy. Wpisywanie wprost poleceń kompilatora na dłuższą metę byłoby bardzo męczące, zwłaszcza jeżeli program rozsiany jest w wielu różnych plikach. Do automatyzacji tego procesu służy program make. Działaniem programu make zarządza plik o standardowej nazwie Makefile. Składnia tego pliku jest nastpująca:

cel: plik_źrodłowy1 plik_źródłowy2 ...
  reguła1 (polecenie pozwalające otrzymać cel z plików źródłowych)
  być może kolejna reguła, wykonywana po poprzedniej

Reguły muszą być poprzedzone pojedynczym znakiem tabulacji (a nie np. czterema spacjami).

Dla naszego małego programu, z rodzieloną kompilacją i konsolidacją, plik ten mógłby wyglądać następująco:

gmp: gmp.o
  g++ gmp.o -o gmp -lgmp -lgmpxx

gmp.o: gmp.cpp
  g++ gmp.cpp -c -o gmp.o

Wywołanie w katalogu projektu polecenia make wykona niezbędne polecenia. Program make stara się zbudować pierwszy napotkany w pliku cel (w tym przypadku plik gmp), w tym celu utworzy plik gmp.o według podanego przepisu. Jeżeli plik gmp.cpp zostanie zmieniony, to porównując czasy ostatniej modyfikacji plików make zauważy, że trzeba odpowiednie pliki stworzyć na nowo. Wykonuje więc minimum pracy, jednak cała konieczna praca zostanie wykonana. Aby wymusić kompilację bez zmian w plikach źródłowych, można użyc poznanego wcześniej polecenia touch.

Cele w pliku Makefile nie muszą być plikami – jasne jest, że mogą nie istnieć w momencie wywołania make, ale reguły wcale nie muszą tworzyć podanego celu jako pliku, nie będzie to błędem. Podobnie cel może nie mieć plików źródłowych. W obu tych przypadkach reguły zostaną wykonane za każdym razem, gdy make będzie próbował utworzyć cel. Program make można wywoływać podając cel, wtedy zostaną wykonane odpowiednie reguły celem jego utworzenia (np. make gmp.o). W przypadku braku zadanego celu, make próbuje utworzyć pierwszy napotakany cel w pliku Makefile.

Programu make można używać do innych celów poza kompilacją. W szczególności ta strona HTML jest generowana z plików napisanych w formacie reStructuredText właśnie za pomocą make.

Zadanie

Zasymuluj działanie sprawdzarki z użyciem make. Wybierz dowolne zadanie programistyczne z przedmiotu Podstawy programowania ze sprawdzarki. Stwórz plik Makefile, który:

Oprócz pliku Makefile potrzebne prawdopodobnie będą:

Działanie gotowego rozwiązania może wyglądać tak jak na poniższym filmie. Na filmie make nie wyświetla wykonywanych poleceń celem nie ułatwiania Państwu zbyt bardzo zadania, w praktyce z reguły wykonywane polecenia normalnie się wyświetlają. W prezentowanym rozwiązaniu make test wykonuje zarówno dobre jak i złe testy, inaczej niż w poleceniu zadania:

Rozwiązania proszę przesyłać w postaci jednego skompresowanego pliku zip bądź tar (najlepiej też skompresowanego). Plik ma zawierać jeden katalog o nazwie będącej loginem do serwisu, reszta plików powinna się znajdować w tym katalogu. Pliki tekstowe powinny zawierać polskie znaki (oczywiście jeżeli są konieczne) w kodowaniu UTF-8.