Elementy składowe linii poleceń

Dotychczas poznaliśmy najprostszą postać linii poleceń. Linia składała się z nazwy polecenia, po której mogły wystąpić opcje, a następnie jeden lub więcej argumentów będących nazwami plików. Na końcu linii mogło dodatkowo wystąpić przeadresowanie standardowego wejścia i wyjścia.

W rzeczywistości budowa linii polecenia może być znacznie bardziej wyrafinowana. Interpretacją linii przed wywołaniem polecenia zajmuje się jak wiemy fragment programu obsługującego komunikację z użytkownikiem (powłoki), zwany interpreterem poleceń. Reaguje on na następujące znaki specjalne zawarte w linii polecenia:

* ? > < | ' " ` $ & # \

Nie należy używać ich do innych celów, na przykład do nazywania plików. Znakiem odwrotnego ukośnika \ można poprzedzić dowolny inny znak, aby był on potraktowany przez interpreter poleceń jako zwykły znak. Umieszczony na końcu linii umożliwia kontynuowanie pisania polecenia w kolejnej linii.

Wzorce nazw plików

Pliki przekazane poleceniu jako argumenty mogą być podane jawnie nazwami. W przypadku większej ich liczby bywa to jednak niewygodne. Argumenty mające podobne nazwy można zapisywać skrótowo wzorcami.

Wzorzec podobnie jak nazwa jest ciągiem znaków, jednakże obok liter, cyfr i innych znaków dozwolonych w nazwach plików elementami wzorca mogą być pewne znaki specjalne. Nazywać je będziemy metaznakami.

Za interpretację metaznaków (nadawanie im specjalnego znaczenia) odpowiedzialny jest używany interpreter poleceń. Wzorzec występujący w linii polecenia zastępowany jest przed wykonaniem polecenia wszystkimi pasującymi doń nazwami istniejących plików (zwykle będą to pliki z bieżącego katalogu).

Najprostszy wzorzec składa się z samego metaznaku *. Pasuje do niego dowolna nazwa pliku. Interpreter zastąpi ten wzorzec nazwami wszystkich plików, a następnie spowoduje wykonanie polecenia.

$ pwd
/home/student1
$ ls
postacie
przybysze
wszyscy
$ echo *
postacie przybysze wszyscy
$ _

Pamiętamy, że polecenie echo wypisuje wszystkie swoje argumenty. Argumenty otrzymywane przez to polecenie zostały już jednak wstępnie zmodyfikowane przez interpreter. Zamiast jednego pojawiły się aż trzy argumenty.

Jak widzieliśmy powyżej, polecenia echo można użyć aby przekonać się, jakie pliki opisuje dany wzorzec. Zanim wydamy potencjalnie niebezpieczne polecenie dotyczące plików opisanych pewnym wzorcem (np. polecenie rm), warto sprawdzić poleceniem echo, jakich plików będzie dotyczyło.

Do dalszych ćwiczeń potrzebny nam będzie katalog zawierający więcej plików. Pliki można szybko rozmnożyć używając poznanych już poleceń cp i cat. Zostawiamy to czytelnikowi jako samodzielne ćwiczenie, którego efektem powinna być następująca zawartość katalogu bieżącego.

$ ls -x
lekcja1    lekcja2   lekcja3    lekcja4  postacie
przybysze  wykład1   wykład2    wszyscy  zadanie1  
zadanie2   zadanie3  zadanie12
$ echo *
lekcja1    lekcja2   lekcja3  lekcja4   postacie  
przybysze  wykład1   wykład2  wszyscy   zadanie1
zadanie2   zadanie3
$ ls -x *
lekcja1    lekcja2    lekcja3    lekcja4  postacie
przybysze  wykład1    wykład2    wszyscy  zadanie1
zadanie2   zadanie3   zadanie12
$ _

Użyta powyżej opcja -x polecenia ls powoduje wielokolumnowe wypisanie zawartości katalogu. Natomiast użycie wzorca jako argumentu ls spowodowało wypisanie wyłącznie nazw pasujących do wzorca --- akurat w tym przypadku były to nazwy wszystkich plików.

Jeśli chcemy przekonać się, jakie lekcje znajdują się w katalogu bieżącym, musimy użyć innego wzorca.

$ ls lekc*
lekcja1
lekcja2
lekcja3
lekcja4
$ _

Wzorzec lekc* pasuje do wszystkich nazw zaczynających się od ciągu liter ,,lekc'', po którym mogą wystąpić (ale nie muszą) dowolne inne znaki. Po prostu metaznak * pasuje do dowolnego ciągu znaków, natomiast zwykłe znaki występujące we wzorcu traktowane są literalnie i muszą wystąpić w argumencie. Popatrzmy jeszcze na kilka przykładów.

$ ls w*
wykład1
wykład2
wszyscy
$ ls *2
lekcja2
wykład2
zadanie2
zadanie12
$ ls *s*
postacie
przybysze
wszyscy
$ _

W ostatnim przykładzie metaznak * wystąpił we wzorcu dwukrotnie. Do tego wzorca pasują wszystkie nazwy zawierające literę ,,s''.

Inny metaznakiem jest ?. Element ten pasuje do dowolnego pojedynczego znaku.

$ ls lekcja?
lekcja1
lekcja2
lekcja3
lekcja4
$ ls *s??
przybysze
wszyscy
$ _

Każde wystąpienie metaznaku ? (jak w drugim przykładzie powyżej) musi odpowiadać osobnemu znakowi. Popatrzmy na różnicę pomiędzy poznanymi metaznakami.

$ ls -x zadanie*
zadanie1   zadanie2   zadanie3   zadanie12
$ ls -x zadanie?
zadanie1   zadanie2   zadanie3
$ _

Nawiasy kwadratowe [ i ] są metaznakami, które muszą wystąpić razem. Służą do budowania klas znaków. Wewnątrz nich można umieścić dowolny ciąg znaków. Taka konstrukcja tworzy pojedynczy element wzorca zwany klasą znaków. Pasuje on do dowolnego, pojedynczego znaku spośród podanych.

$ ls lekcja[12]
lekcja1
lekcja2
$ ls *[23]
lekcja2
lekcja3
wykład2
zadanie2
zadanie3
$ ls -x *[0123456789]
lekcja1    lekcja2    lekcja3    lekcja4    wykład1
wykład2    zadanie1   zadanie2   zadanie3   zadanie12
$ _

Aby nie wypisywać zbyt wielu znaków, można posłużyć się skrótem. Umieszczenie wewnątrz nawiasów kwadratowych pary znaków rozdzielonych myślnikiem równoważne jest umieszczeniu tam wszystkich znaków pomiędzy wskazanymi znakami.

$ ls -x *[0-9]
lekcja1    lekcja2    lekcja3    lekcja4    wykład1
wykład2    zadanie1   zadanie2   zadanie3   zadanie12
$ ls -x [wz]*[0-9]
wykład1    wykład2    zadanie1   zadanie2   zadanie3
zadanie12
$ _

Cudzysłowy

Nie wszystkie argumenty polecenia muszą być nazwami plików. Tak było na przykład w przypadku polecenia who. Podobnie zachowują się polecenia przeszukiwania plików, które poznamy podczas następnej lekcji. Ich pierwszym argumentem jest poszukiwany tekst, mogący przecież zawierać dowolne znaki (również spacje). Taki argument nie powinien być potraktowany jako wzorzec (w przypadku gdy zawiera spację mógłby być potraktowany nawet jako dwa wzorce).

Interpreter poleceń jest jednak ,,nadgorliwy'' --- traktuje on każdy argument (poza opcją) jako wzorzec nazwy pliku. Taka uniwersalność umożliwia elastyczne dopasowywanie systemu do lokalnych potrzeb, np. zmienianie nazw poleceń. Interpretacja argumentów przez powłokę nie może więc zależeć od nazwy polecenia. Nie dotyczy to tylko poleceń wbudowanych powłoki takich jak cd, ale jest ich niewiele.

W sytuacjach gdy argument nie powinien być traktowany jako wzorzec należy użyć cudzysłowów. Otaczamy nimi dowolny ciąg znaków, który powinien być dosłownie przekazany programowi realizującemu polecenie (bez interpretacji przez powłokę).

Polecenie tr (od ang. transliterate) służy do zamiany znaków w pliku. Omówimy je dokładnie podczas następnej lekcji, na razie skorzystamy tylko z jego najprostszej postaci.

$ cat tekst
* Linia z * gwiazdkami
* które mają zmienić * się
* w znaki zapytania.
$ tr "*" "?" <tekst
? Linia z ? gwiazdkami
? które mają zmienić ? się
? w znaki zapytania.
$ _

Polecenie tr czyta ze standardowego wejścia (które w naszym przykładzie było przeadresowane), zaś pisze na standardowe wyjście (w tym przypadku na ekran terminala). Argumenty powinny być ciągami znaków. Podczas przepisywania z wejścia na wyjście po napotkaniu znaku występującego w pierwszym argumencie jest on zastępowany odpowiadającym mu znakiem z drugiego argumentu. W przykładzie powyżej oba ciągi miały długość 1.

Zobaczmy, co byłoby, gdybyśmy pominęli cudzysłowy.

$ ls
postacie
przybysze
tekst
wszyscy
$ tr * ? <tekst
* Lsnsb z * gwsbzdkbms
* kyórz mbją zmsznsć * zsę
* w znbks zbpyybnsb.
$ _

Co się stało? Przypomnijmy sobie działanie interpretera poleceń. Przed wykonaniem polecenia tr zastąpił on wzorzec * ciągiem pasujących do niego nazw plików: postacie przybysze tekst wszyscy. W ten sposób argumentami widzianymi przez polecenie tr były dwie pierwsze nazwy, potraktowane przez polecenie jako ciągi znaków.

Podobnie do cudzysłowów działają apostrofy. Różnice ujawniają się dopiero przy zaawansowanym programowaniu w języku powłoki.

$ tr '*' '?' <tekst
? Linia z ? gwiazdkami
? które mają zmienić ? się
? w znaki zapytania.
$ _

Odradzamy jednak ich używanie, ponieważ łatwo pomylić je z ,,odwrotnymi'' apostrofami (apostrof skierowany w drugą stronę) mającymi zupełnie inne znaczenie dla interpretera poleceń. Otoczony nimi ciąg traktowany jest jako samodzielna linia polecenia, wykonywana przed właściwą linią. Zastępowana jest ona tekstem, który wyprodukowało jej wykonanie. Więcej na ten temat powiemy później, na razie tylko króciutki przykład.

$ echo Dziś jest 'date'
Dziś jest date
$ echo Dziś jest `date`
Dziś jest Mon Jan11 8:45:00 MEZ 1993

Wiele użytkowych programów także używa wzorców. Jednym z nich jest find. W najprostszej postaci potrafi on znaleźć wszystkie pliki o nazwie podanej wzorcem (poczynając od bieżącego lub wskazanego katalogu).

$ ls
lekcja1    lekcja2    lekcja3    lekcja4    wykład1
wykład2    zadanie1   zadanie2   zadanie3   zadanie12
$ find -name "lekcja*"
lekcja1
lekcja2
lekcja3
lekcja4
$ _

Uwaga: w poleceniu find wzorzec musi być podany w cudzysłowie, żeby nie został przedwcześnie rozwinięty przez interpreter powłoki, lecz dopiero przez sam program.