Jedną z najczęstszych akcji jest wypisanie, wydruk (print) części
lub całości danych wejściowych. Do zrobienia prostego wydruku (wyjścia)
używamy instrukcji print. Instrukcja printf daje możliwość
bardziej wyszukanego formatowania. Obie opisano w tym rozdziale.
print
Instrukcja print wykonuje wydruk za pomocą prostego,
standaryzowanego formatowania. Określamy tylko, w postaci listy separowanej
przecinkami, łańcuchy lub liczby do wypisania. Przy drukowaniu są
one rozdzielane pojedynczymi spacjami, a na końcu dołączany jest znak nowej
linii. Instrukcja ta wygląda tak:
print elem1, elem2, ...
Całość listy elementów może opcjonalnie być ujęta w nawiasy. Nawiasy są
niezbędne jeśli któryś z elementów jest wyrażeniem z operatorem
relacyjnym. Inaczej mogłoby ono być pomylone z przekierowaniem
(zob. 6.6. Przekierowanie wyjścia print i printf).
Elementy do wypisania mogą być stałymi łańcuchami lub liczbami, polami
bieżącego rekordu (jak $1), zmiennymi, czy wreszcie dowolnymi
wyrażeniami awk. Wartości numeryczne są przekształcane na łańcuchy,
a następnie wypisywane.
Instrukcja print jest całkowicie ogólna, jeśli chodzi o to,
jakie wartości wypisać. Jednak, z dwoma wyjątkami, nie można
wyszczególnić jak mają one zostać wypisane -- w ilu kolumnach, czy
stosować notację wykładniczą czy nie, i tak dalej.
(Opis wyjątków, zob. 6.3. Separatory wyjścia
i 6.4. Sterowanie wyjściem numerycznym przez print.)
W tym celu potrzebujemy instrukcji printf
(zob. 6.5. Wymyślne wyjście dzięki instrukcji printf).
Zwykłe polecenie `print', bez żadnych elementów, jest równoważnikiem
`print $0': wypisuje cały bieżący rekord.
Do wypisania pustego wiersza stosujemy `print ""', gdzie ""
jest łańcuchem pustym.
Do wypisania stałego kawałka tekstu stosujemy stałą łańcuchową, jak np.
"Nie panikuj", jako jeden element. Jeżeli zapomnimy o znakach
cudzysłowu, to tekst zostanie potraktowany jako wyrażenie awk
i prawdopodobnie otrzymamy błąd. Należy pamiętać, że pomiędzy każdymi
dwoma elementami wypisywana jest spacja.
Każda z instrukcji print generuje co najmniej jeden wiersz wyjścia.
Ale nie jest ograniczona do jednego wiersza. Jeżeli wartością któregoś z
łańcuchów jest łańcuch zawierający znak nowej linii, to znak ten jest
wypisywany razem z resztą łańcucha. Pojedyncze print może w ten
sposób stworzyć dowolną liczbę wierszy.
printOto przykład wypisywania łańcucha, który zawiera wbudowane znaki nowej linii (`\n' jest sekwencją specjalną, służącą do przedstawiania znaku nowej linii, zob. 4.2. Sekwencje specjalne):
$ awk 'BEGIN { print "wiersz jeden\wiersz dwa\nwiersz trzy" }'
-| wiersz jeden
-| wiersz dwa
-| wiersz trzy
Oto przykład wypisujący pierwsze dwa pola każdego rekordu wejściowego, ze spacją między nimi:
$ awk '{ print $1, $2 }' inventory-shipped
-| Jan 13
-| Feb 15
-| Mar 15
...
Typową pomyłką przy stosowaniu instrukcji print jest pominięcie
przecinka między dwoma elementami. Często w wyniku na wyjściu elementy są
zestawione razem, bez spacji. Przyczyną jest to, że
postawienie obok siebie dwu wyrażeń łańcuchowych oznacza w awk
ich konkatenację. Oto ten sam program bez przecinka:
$ awk '{ print $1 $2 }' inventory-shipped
-| Jan13
-| Feb15
-| Mar15
...
Dla osoby nie znającej pliku `inventory-shipped', żaden z powyższych
przykładów wyjścia nie ma zbyt dużego sensu. Wiersz nagłówka na
początku nadałby mu jasności. Dodajmy nagłówek do naszej tabeli miesięcy
($1) i wysłanych zielonych paczek ($2). Zrobimy to
wykorzystując wzorzec BEGIN
(zob. 8.1.5. Wzorce specjalne BEGIN i END) do
wymuszenia jednokrotnego wypisania nagłówka:
awk 'BEGIN { print "Mies. Paczki"
print "----- ------" }
{ print $1, $2 }' inventory-shipped
Odgadłeś już, co się stanie? Po uruchomieniu program wypisze:
Mies. Paczki ----- ------ Jan 13 Feb 15 Mar 15 ...
Nagłówki i dane tabeli nie są wyrównane! Możemy to poprawić wypisując trochę spacji między naszymi dwoma polami:
awk 'BEGIN { print "Mies. Paczki"
print "----- ------" }
{ print $1, " ", $2 }' inventory-shipped
Można sobie wyobrazić, że taka metoda wyrównywania kolumn może stać się dość
skomplikowana, jeśli do poprawienia mamy wiele kolumn. Zliczanie spacji dla
dwóch czy trzech kolumn może być proste, lecz przy większej liczbie łatwo
się pogubić. Z tego powodu stworzono instrukcję printf
(zob. 6.5. Wymyślne wyjście dzięki instrukcji printf);
jedną z jej specjalności jest wyrównywanie kolumn danych.
Nawiasem mówiąc, można kontynuować instrukcję print czy
printf po prostu stawiając znak nowej linii po przecinku
(zob. 2.6. Instrukcje awk a wiersze).
Jak uprzednio wspomniano, instrukcja print zawiera listę
rozdzielonych przecinkami elementów. Na wyjściu elementy te są normalnie
oddzielane spacjami. Tak jednak być nie musi -- pojedyncza spacja jest
tylko domyślna. Można podać dowolny łańcuch znaków, który będzie
stosowany jako separator pól wyjściowych (output field separator).
Robi się to przez przypisanie go zmiennej wbudowanej OFS.
Początkową jej wartością jest łańcuch " ", czyli pojedyncza
spacja.
Wyjście z całej instrukcji print nazywamy rekordem wyjściowym
(output record). Każda instrukcja print wypisuje jeden rekord
wyjściowy a następnie łańcuch zwany separatorem rekordów wyjściowych
(output record separator). Łańcuch ten jest określany przez zmienną
wbudowaną ORS. Początkową wartością ORS jest łańcuch
"\n", tj. znak nowej linii. Zatem, normalnie, każda zwykła instrukcja
print tworzy osobny wiersz.
Sposób, w jaki rozdzielane są pola i rekordy wyjściowe, może być zmieniany
przez przypisanie nowych wartości zmiennym OFS i/lub ORS.
Zwyczajowym miejscem takiego przypisania jest wnętrze reguły BEGIN
(zob. 8.1.5. Wzorce specjalne BEGIN i END), tak
by odbyło się ono przed przetworzeniem czegokolwiek z wejścia. Można to
również zrobić za pomocą przypisań w wierszu poleceń, przed nazwami
plików wejściowych, lub stosując opcję `-v' wiersza poleceń
(zob. 14.1. Opcje wiersza poleceń).
Poniższy przykład wypisuje pierwsze i ostatnie pole każdego rekordu wejściowego, rozdzielając je średnikami, z pustym wierszem dodanym po każdym wierszu:
$ awk 'BEGIN { OFS = ";"; ORS = "\n\n" }
> { print $1, $2 }' BBS-list
-| aardvark;555-5553
-|
-| alpo-net;555-3412
-|
-| barfly;555-7685
...
Jeżeli wartość ORS nie zawiera znaku nowej linii, to całość wyjścia
programu będzie połączona w jednym wierszu, chyba że wyemitujemy znaki nowej
linii w jakiś inny sposób.
print
Gdy stosujemy instrukcję print to wypisania wartości numerycznych,
awk wewnętrznie przekształca liczbę na łańcuch znaków i wypisuje
ten łańcuch. Do wykonania tej konwersji awk wykorzystuje funkcję
sprintf
(zob. 12.3. Funkcje wbudowane działające na łańcuchach).
Na razie wystarczy powiedzieć, iż funkcja sprintf akceptuje
specyfikację formatu, która mówi jej jak formatować liczby (lub
łańcuchy), i że istnieje wiele różnych sposobów, na jakie można
formatować liczby. Rozmaite specyfikacje formatu omawiane są pełniej
w 6.5.2. Litery sterujące formatem.
Zmienna wbudowana OFMT zawiera domyślną specyfikację formatu, który
print używa z sprintf gdy chce przekształcić liczbę na
łańcuch do wypisania. Domyślną wartością OFMT jest "%.6g".
Podając jako wartość OFMT inne specyfikatory formatu zmieniamy
sposób, w jaki print będzie wypisywał liczby. Jako krótki przykład:
$ awk 'BEGIN {
> OFMT = "%.0f" # wypisz liczby jako całkowite (zaokrągla)
> print 17.23 }'
-| 17
Zgodnie ze standardem POSIX, zachowanie się awk będzie
niezdefiniowane, jeśli OFMT zawiera coś innego niż specyfikację
konwersji zmiennoprzecinkowej (c.k.).
printf
Jeżeli potrzebujemy dokładniejszej kontroli nad formatem wyjściowym niż to
daje print, wykorzystajmy printf. Za pomocą printf
można określać szerokość, jaką ma mieć każda z pozycji, i rozmaite opcje
formatowania liczb (jak podstawa do stosowania, liczba cyfr do wypisania po
kropce dziesiętnej). Robi się to podając łańcuch, zwany łańcuchem
formatu, który steruje sposobem i miejscem wypisania pozostałych
argumentów.
printf
Instrukcja printf wygląda tak:
printf format, elem1, elem2, ...
Całość listy argumentów może być opcjonalnie ujęta w nawiasy. Nawiasy są
konieczne jeśli któryś z elementów jest wyrażeniem używa operatora
relacyjnego `>'. W przeciwnym razie mogłoby ono zostać
pomylone z przekierowaniem
(zob. 6.6. Przekierowanie wyjścia print i printf).
Różnicę pomiędzy printf a print stanowi argument format.
Jest to wyrażenie, którego wartość jest brana jako łańcuch; określa w jaki
sposób wypisać każdy z pozostałych argumentów. Nazywa się je
łańcuchem formatu.
Łańcuch formatu jest bardzo podobny do stosowanego w funkcji bibliotecznej
ANSI C printf. Większość formatu to tekst, jaki ma być
wypisany dosłownie. W tekście rozsiane są specyfikatory formatu, po
jednym na element. Każdy specyfikator formatu określa sposób wypisania
argumentu mającego tę samą pozycję na liście argumentów, co specyfikator
w łańcuchu formatu.
Instrukcja printf nie dołącza samoczynnie znaku nowej linii
do tworzonego wyjścia. Wypisuje tylko to, co wyszczególnia łańcuch formatu.
Zatem, jeżeli chcemy znaku nowej linii, to musimy go zawrzeć w łańcuchu
formatu. Zmienne separatorów wyjścia OFS and ORS nie mają
wpływu na instrukcje printf. Na przykład:
BEGIN {
ORS = "\nAU!\n"; OFS = "!"
msg = "Nie panikuj!"; printf "%s\n", msg
}
Ten program nadal wypisuje przyjazny komunikat `Nie panikuj!'.
Specyfikator formatu rozpoczyna się znakiem `%' a kończy
literą sterująca formatem; mówi ona instrukcji printf, jak
powinien zostać wypisany pojedynczy element. (Chcąc faktycznie uzyskać
wypisanie znaku `%', piszemy `%%'.) Litera sterująca formatem
określa, jaki rodzaj wartości wypisać. Reszta specyfikatora formatu
zbudowana jest z opcjonalnych modyfikatorów, będących parametrami,
jakie mają zostać użyte, jak np. szerokość pola.
Oto lista liter sterujących formatem:
c
d
i
e
E
printf "%4.3e\n", 1950wypisze `1.950e+03', o ogółem czterech cyfrach znaczących, z których trzy są po kropce dziesiętnej. The `4.3' są modyfikatorami, omówionymi poniżej. `%E' używa `E' zamiast `e' w wyjściu.
f
printf "%4.3f", 1950wypisze `1950.000', z czterema cyfrach znaczących, z których trzy są po kropce dziesiętnej. The `4.3' są modyfikatorami, omówionymi poniżej.
g
G
o
s
u
awk
są zmiennoprzecinkowe. Obsługiwany głównie dla zgodności z C.)
x
X
%
Przy stosowaniu liter sterujących formatem liczb całkowitych do wartości
spoza zakresu długich całkowitych w C (long integer), gawk
przełączy się na specyfikator formatu `%g'. Inne wersje awk
mogą wypisywać niepoprawne wartości lub robić coś całkiem innego (c.k.).
printfSpecyfikacja formatu może zawierać także modyfikatory, decydujące o tym, jaka część wartości elementu będzie wypisana i ile miejsca zajmie. Modyfikatory mogą wystąpić pomiędzy znakiem `%' a literą sterującą formatem. W przykładach niżej zastosowano symbol wyliczenia "*" do przedstawienia spacji w wyjściu. Oto możliwe modyfikatory, w kolejności, w jakiej mogą się pojawić:
-
printf "%-4s", "foo"wypisuje `foo*'.
spacja
+
#
0
szer
printf "%4s", "foo"wypisuje `*foo'. Wartość szer jest szerokością minimalną, nie maksymalną. Jeżeli wartość elementu wymaga więcej niż szer znaków, może być tak szeroka, jak to jest niezbędne. Zatem,
printf "%4s", "foobar"wypisuje `foobar'. Poprzedzenie szer znakiem minus powoduje, że wyjście będzie dopełniane spacjami z prawej, zamiast z lewej.
.dokł
printf "%.4s", "foobar"wypisuje `foob'.
Obsługiwana jest możliwość dynamicznych szer i dokł (na przykład,
"%*.*s") zapewniana przez printf z biblioteki C. Zamiast
podawania w łańcuchu formatu wartości szer i/lub dokł wprost,
można je przekazać w liście argumentów. Na przykład:
w = 5 p = 3 s = "abcdefg" printf "%*.*s\n", w, p, s
jest ściśle równoważne temu:
s = "abcdefg" printf "%5.3s\n", s
Oba programy wypisują `**abc'.
Wcześniejsze wersje awk nie obsługują powyższej własności.
Jeżeli musimy użyć takiej wersji, można zasymulować tę cechę wykorzystując
do budowy łańcucha formatu konkatenację, jak tu:
w = 5 p = 3 s = "abcdefg" printf "%" w "." p "s\n", s
Nie jest do szczególne łatwe w czytaniu, ale działa.
Programiści C mogą być przyzwyczajeni do używania dodatkowych flag
`l' i `h' w łańcuchach formatu printf. Nie są one poprawne
w awk. Większość implementacji awk milcząco ignoruje te
flagi. Jeżeli w wierszu poleceń podano `--lint'
(zob. 14.1. Opcje wiersza poleceń), gawk będzie ostrzegał o ich
użyciu. Jeżeli podano `--posix', ich użycie jest błędem fatalnym.
printf
A oto, w jaki sposób wykorzystać printf do utworzenia wyrównanej
tabeli:
awk '{ printf "%-10s %s\n", $1, $2 }' BBS-list
powyższe wypisuje nazwy BBS-ów ($1) z pliku `BBS-list' w postaci
łańcucha 10 znaków, wyrównanego do lewej. Za nimi, w tym samym
wierszu, wypisuje też numery telefonów ($2). Tworzy to wyrównaną
dwukolumnową tabelę nazw i numerów telefonicznych:
$ awk '{ printf "%-10s %s\n", $1, $2 }' BBS-list
-| aardvark 555-5553
-| alpo-net 555-3412
-| barfly 555-7685
-| bites 555-1675
-| camelot 555-0542
-| core 555-2912
-| fooey 555-1234
-| foot 555-6699
-| macfoo 555-6480
-| sdace 555-3430
-| sabafoo 555-2127
Zauważyłeś, że nie określiliśmy, że numery telefonów mają być wypisane jako liczby? Musiały być wypisane jako łańcuchy, gdyż są rozdzielane kreską. Jeśli spróbowalibyśmy wypisać je jako liczby, to wszystkim, co byśmy otrzymali, byłyby pierwsze trzy cyfry, `555'. Wprowadziłoby to niezłe zamieszanie.
Nie podawaliśmy szerokości numerów telefonicznych, ponieważ występują jako ostatnie w wierszach. Nie musimy po nich stawiać spacji.
Można by nawet upiększyć naszą tabelę dodając nagłówki nad kolumnami.
Zastosujemy do tego wzorzec BEGIN
(zob. 8.1.5. Wzorce specjalne BEGIN i END),
wymuszając tylko jednorazowe wypisanie nagłówka, na początku programu
awk:
awk 'BEGIN { print "Nazwa Numer"
print "----- -----" }
{ printf "%-10s %s\n", $1, $2 }' BBS-list
Zauważyłeś, że w powyższym przykładzie wymieszaliśmy instrukcje print
i printf? Mogliśmy użyć wyłącznie instrukcji printf
do uzyskania tych samych rezultatów:
awk 'BEGIN { printf "%-10s %s\n", "Nazwa", "Numer"
printf "%-10s %s\n", "-----", "-----" }
{ printf "%-10s %s\n", $1, $2 }' BBS-list
Wypisując nagłówek każdej z kolumn za pomocą takiej samej specyfikacji formatu, co zastosowana dla elementów tej kolumny, upewniliśmy się, że nagłówki zostaną wyrównane dokładnie tak samo jak kolumny.
Fakt, iż ta sama specyfikacja formatu jest używana trzykrotnie, można uwypuklić przechowując ją w zmiennej, w ten sposób:
awk 'BEGIN { format = "%-10s %s\n"
printf format, "Nazwa", "Numer"
printf format, "-----", "-----" }
{ printf format, $1, $2 }' BBS-list
Sprawdź, czy potrafisz użyć instrukcji printf do wyrównania nagłówków
i danych tabeli dla naszego przykładu z plikiem `inventory-shipped',
omawianego wcześniej w sekcji o instrukcji print
(zob. 6.1. Instrukcja print).
print i printf
Do tej pory zajmowaliśmy się tylko wyjściem piszącym na standardowe wyjście,
zwykle terminal. Zarówno print jak i printf potrafią również
wysyłać swoje wyjście w inne miejsca. Nazywamy to przekierowaniem
(redirection).
Przekierowanie występuje po instrukcji print lub printf .
Przekierowania w awk zapisywane są tak samo jak w poleceniach
powłoki, za wyjątkiem tego, że są zapisane wewnątrz programu awk.
Mamy trzy postacie przekierowania wyjścia: wyjście do pliku,
wyjście dopisywane do pliku i wyjście poprzez potok do innego polecenia.
Wszystkie pokazano dla instrukcji print, ale działają identycznie
dla printf.
print elementy > plik-wyj
awk może zapisać listę BBS-ów do pliku
`name-list' a listę numerów telefonów do pliku `phone-list'.
Oba pliki wyjściowe zawierają po jednej nazwie lub numerze na wiersz.
$ awk '{ print $2 > "phone-list"
> print $1 > "name-list" }' BBS-list
$ cat phone-list
-| 555-5553
-| 555-3412
...
$ cat name-list
-| aardvark
-| alpo-net
...
print elementy >> plik-wyj
awk jest dołączane na koniec pliku.
Jeżeli plik-wyj nie istnieje, to jest tworzony.
print elementy | polecenie
awk. Jego wartość jest przekształcana na łańcuch, którego zawartość
daje polecenie powłoki, jakie ma być uruchomione.
Na przykład, poniższe tworzy dwa pliki, listę niesortowanych nazw BBS-ów i
listę posortowaną w odwrotnym porządku alfabetycznym:
awk '{ print $1 > "names.unsorted"
command = "sort -r > names.sorted"
print $1 | command }' BBS-list
Tutaj lista niesortowana jest zapisywana zwykłym przekierowaniem, podczas
gdy lista posortowana zapisywana jest za pomocą potokowania przez
narzędzie sort.
Kolejny przykład korzysta z przekierowania do wysłania wiadomości na listę
pocztową `bug-system'. Może to być przydatne gdy w pojawiły się
kłopoty w skrypcie awk uruchamianym okresowo do konserwacji systemu.
report = "mail bug-system"
print "Awk script failed:", $0 | report
m = ("at record number " FNR " of " FILENAME)
print m | report
close(report)
Wiadomość budowana jest za pomocą konkatenacji (złączenia łańcuchów)
i zapisywana w zmiennej m. Następnie jest wysyłana potokiem do
programu mail.
Wywołujemy tu funkcję close, gdyż dobrym nawykiem jest zamykać potok
zaraz po przesłaniu do niego zamierzonego wyjścia.
Zob. 6.8. Zamykanie potoków oraz plików wejściowych i wyjściowych,
gdzie jest o tym więcej napisane. Ten przykład ilustruje również
zastosowanie zmiennej do reprezentacji pliku lub polecenia:
nie jest konieczne używanie zawsze stałej łańcuchowej. Stosowanie zmiennej
jest na ogół dobrym rozwiązaniem, ponieważ awk wymaga, by wartość
łańcucha była za każdym razem zapisana tak samo.
Przekierowanie wyjścia przy użyciu `>', `>>' lub `|' prosi system o otwarcie pliku lub potoku tylko jeśli do konkretnego pliku lub polecenia, które podaliśmy, nasz program jeszcze nie pisał, albo jeśli je zamknięto po ostatnim zapisie.
Jak wspomniano wcześniej
(zob. 5.8.8. Podsumowanie wariantów getline),
wiele
implementacji awk ogranicza ilość potoków, jakie program
awk może mieć otwarte, do tylko jednego! W gawk nie ma
takiego ograniczenia. Można otworzyć tyle potoków, na ile zezwoli
stosowany system operacyjny.
gawkZgodnie z konwencją, pracujące programy mają trzy strumienie wejścia/wyjścia już dostępne dla nich do odczytu i zapisu. Są one znane jako standardowe wejście, standardowe wyjście i standardowe wyjście błędów. Strumienie te domyślnie są połączone z naszym terminalem, ale często są przekierowywane za pomocą powłoki, poprzez operatory `<', `<<', `>', `>>', `>&' i `|'. Standardowe wyjście błędów jest na ogół używane do zapisywania komunikatów o błędach. Powodem, dla którego mamy dwa odrębne strumienie, standardowe wyjście i standardowe wyjście błędów, jest to, że można je wówczas osobno przekierowywać.
W innych implementacjach awk, jedyną metodą zapisania komunikatu
o błędzie na standardowym wyjściu błędów w programie awk jest:
print "Wykryto poważny błąd!" | "cat 1>&2"
Działa to dzięki otwarciu potoku do polecenia powłoki, które ma
dostęp do standardowego strumienia błędów, jaki dziedziczy po procesie
awk. Jest to wysoce nieeleganckie. Jest też nieefektywne, gdyż
wymaga odrębnego procesu. Ludzie piszący programy awk często
tego nie robią.
Zamiast tego, wysyłają komunikaty o błędach na terminal, tak:
print "Wykryto poważny błąd!" > "/dev/tty"
Zwykle na to ten sam efekt, ale nie zawsze: chociaż standardowym strumieniem
błędów jest na ogół terminal, to może ono zostać przekierowane, i gdy się
tak dzieje, pisanie na terminal nie jest poprawne. W rzeczywistości, jeżeli
awk uruchamiany jest z zadania tle, możemy w ogóle nie mieć
terminala. Wówczas otwarcie `/dev/tty' się nie powiedzie.
gawk udostępnia specjalne nazwy plików do dostępu do trzech
standardowych strumieni. Przy przekierowaniu wejścia lub wyjścia
w gawk jeśli nazwa pliku pasuje do jednej z tych nazw specjalnych,
to gawk używa wprost strumienia, który ona oznacza.
awk (na ogół powłokę).
Dopóki nie podejmujemy specjalnych starań w powłoce, z której wołamy
awk, dostępne są tylko deskryptory 0, 1 i 2.
Nazwy plików `/dev/stdin', `/dev/stdout' i `/dev/stderr' są synonimami (aliasami) dla, odpowiednio, `/dev/fd/0', `/dev/fd/1' i `/dev/fd/2', ale są bardziej zrozumiałe.
Prawidłowym sposobem wypisywania komunikatów o błędach w programie
gawk jest użycie `/dev/stderr', jak tu:
print "Wykryto poważny błąd!" > "/dev/stderr"
gawk udostępnia też specjalne nazwy plików dające dostęp do
informacji o pracującym procesie gawk. Każdy z tych "plików"
udostępnia jeden rekord danych. Chcąc odczytać je więcej niż raz, musimy
je zamknąć funkcją close
(zob. 6.8. Zamykanie potoków oraz plików wejściowych i wyjściowych).
Tymi nazwami są:
$1
getuid (rzeczywisty
identyfikator numeryczny użytkownika).
$2
geteuid (efektywny
identyfikator numeryczny użytkownika).
$3
getgid (rzeczywisty
identyfikator numeryczny grupy).
$4
getegid (efektywny
identyfikator numeryczny grupy).
getgroups.
(Nie wszystkie systemy obsługują przynależność do wielu grup.)
Powyższe specjalne nazwy plików mogą być stosowane w wierszu poleceń jako
pliki danych, jak i do przekierowań wejścia/wyjścia w programie awk.
Nie można ich stosować jako plików źródłowych opcji `-f'.
Rozpoznawanie powyższych specjalnych nazw plików jest wyłączone jeśli
gawk jest w trybie zgodności (zob. 14.1. Opcje wiersza poleceń).
Uwaga!: Interpretacja tych nazw plików wykonywana jest przez
sam gawk, chyba że nasz system faktycznie posiada katalog
`/dev/fd' (lub dowolny inny z podanych wyżej specjalnych plików).
Na przykład, zastosowanie `/dev/fd/4' jako wyjścia w rzeczywistości
będzie pisać do pliku o deskryptorze 4, a nie do nowego deskryptora pliku,
który został zduplikowany (przez dup) z deskryptora 4. W większości
przypadków nie ma to znaczenia; jednak, istotne jest by nie zamykać
plików związanych z deskryptorami 0, 1 i 2. Jeżeli zamkniemy jeden z nich,
spowoduje to nieprzewidywalne zachowanie.
Pliki specjalne dające dostęp do informacji związanej z procesem znikną
w przyszłych wersjach gawk.
Zob. C.3. Prawdopodobne przyszłe rozszerzenia.
Jeśli podczas wykonania programu awk ta sama nazwa pliku lub
polecenia powłoki użyta jest
z getline (zob. 5.8. Odczyt bezpośredni przez getline)
więcej niż raz, plik jest otwierany (lub polecenie wykonywane) tylko
za pierwszym razem. W tym momencie z pliku czy polecenia czytany jest
pierwszy rekord wejścia. Przy następnym użyciu tego samego pliku lub
polecenia z getline, czytany jest z niego kolejny rekord, i tak dalej.
Podobnie, gdy plik lub potok jest otwierany do wyprowadzenia wyników,
nazwa z nim skojarzona jest zapamiętywana przez awk, a kolejne zapisy
do tego samego pliku czy polecenia są dołączane do poprzednich. Plik lub
potok pozostaje otwarty aż do zakończenia pracy awk.
Wynika stąd, że jeśli chcemy zacząć czytanie tego samego pliku od początku
albo powtórnie uruchomić polecenie powłoki (zamiast czytania dalszego ciągu
jego wyjścia), to musimy podjąć specjalne kroki.
To, co musimy zrobić, to użycie funkcji close, jak niżej:
close(nazwapliku)
lub
close(polecenie)
Argumentem nazwapliku lub polecenie może być dowolne wyrażenie. Jego wartość musi dokładnie odpowiadać łańcuchowi, jaki był użyty do otwarcia pliku lub uruchomienia polecenia (łącznie ze spacjami i innymi "nieistotnymi" znakami). Na przykład, jeżeli otwieramy potok za pomocą:
"sort -r names" | getline foo
to musimy go zamknąć tak:
close("sort -r names")
Po wykonaniu wywołania tej funkcji następne getline z tego pliku czy
polecenia, albo następne print lub printf do tego pliku czy
polecenia, ponownie otworzy plik lub uruchomi polecenie.
Ponieważ wyrażenie użyte do zamknięcia pliku lub potoku musi dokładnie odpowiadać wyrażeniu użytemu do jego otwarcia (uruchomienia), dobrą praktyką jest stosowanie zmiennej do przechowania nazwy pliku (polecenia). Poprzedni przykład miałby postać
sortcom = "sort -r names" sortcom | getline foo ... close(sortcom)
Pomaga to uniknąć trudnych do znalezienia błędów typograficznych
w programach awk.
Oto kilka powodów, dla których może zachodzić potrzeba zamknięcia pliku wyjściowego:
awk. Zamknij plik gdy tylko skończysz do niego pisać; następnie
możesz zacząć odczyt za pomocą getline.
awk.
Jeżeli nie zamkniemy plików, możemy ostatecznie wyczerpać systemowy limit
plików otwartych w jednym procesie. Zatem zamknij każdy z nich gdy
skończysz do niego pisać.
mail,
komunikat nie jest faktycznie wysyłany aż do zamknięcia potoku.
mail.
Jeśli wypiszemy kilka wierszy przekierowanych do tego potoku bez jego
zamykania, utworzą pojedynczą wiadomość z kilku wierszy. Natomiast jeśli
zamkniemy potok po każdym wierszu wyjścia, to każdy wiersz będzie tworzył
odrębną wiadomość.
close zwraca wartość zerową jeśli zamknięcie się powiodło.
W przeciwnym razie wartość jest niezerowa. W tym przypadku gawk
przypisuje zmiennej ERRNO łańcuch opisujący błąd, jaki wystąpił.
Jeśli używamy więcej plików niż system pozwala na posiadanie otwartych,
gawk będzie usiłował multipleksować dostępne otwarte pliki
między nasze pliki danych. Jego zdolność do wykonania tego zadania zależy
od udogodnień systemu operacyjnego: może nie zawsze działać. Z tego powodu
dobra praktyka i dobra przenośność doradzają, by zawsze stosować
close w stosunku do plików, z którymi skończono pracę.
Przejdź do pierwszej, poprzedniej, następnej, ostatniej sekcji, spisu treści.