Polecenie awk: wypisywanie pól, separator -F i wzorce warunkowe

Środowisko testoweRodzina RHELAlmaLinux 9.8konto rootSprawdzono 2026-10-29

Polecenie awk to linuksowe narzędzie, które czyta plik tekstowy wiersz po wierszu, dzieli każdy wiersz na pola według spacji lub wskazanego separatora i wybiera tylko pola z wierszy spełniających warunek, aby je wypisać lub policzyć. Na serwerze AlmaLinux 9 zliczono żądania według adresu IP i liczbę wpisów według kodu stanu w przykładowym pliku z logiem dostępu serwera WWW jednym wierszem połączonym potokiem z sort i okazało się, że wszystkie trzy odpowiedzi 404 z dwunastu wierszy to żądania wp-login.php i .env z jednego adresu IP.

Poniższe wyniki uzyskano na koncie root w folderze roboczym serwera AlmaLinux 9.8. Log dostępu, lista kont, zapisy sprzedaży i plik wyników to przykładowe pliki przygotowane do testu, a zawarte w nich adresy IP i nazwy kont również są wartościami przykładowymi.

1️⃣ Podstawowe użycie polecenia awk

  • ↪️ Numery pól i print

awk dzieli każdy odczytany wiersz według spacji i numeruje pola od początku jako $1, $2, $3. Sprawdzono to na pliku scores.txt, w którym imię, wynik i punkty są rozdzielone spacjami.

cat scores.txt
alice   pass  82
bob     fail  47
carol   pass  91
dave    pass  68
erin    fail  55

Nawiasy klamrowe w apostrofach zawierają akcję wykonywaną dla każdego wiersza, a jeśli po print wymienisz numery pól po przecinku, pojawią się tylko te pola. Po wypisaniu pierwszego i trzeciego pola zostają tylko imię i punkty.

awk '{print $1, $3}' scores.txt
alice 82
bob 47
carol 91
dave 68
erin 55

Jeśli usuniesz przecinek między polami i napiszesz $1 $3, obie wartości połączą się bez spacji. Przecinek w print wstawia separator wyjściowy (domyślnie jedna spacja), a wartości zapisane obok siebie bez przecinka łączą się w jeden ciąg znaków.

awk '{print $1 $3}' scores.txt
alice82
bob47
carol91
dave68
erin55

NR to numer dotąd odczytanego wiersza, a NF to liczba pól w tym wierszu. $NF oznacza ostatnie pole, więc wybierzesz ostatnią kolumnę nawet wtedy, gdy liczba pól zmienia się między wierszami.

awk '{print NR, NF, $NF}' scores.txt
1 3 82
2 3 47
3 3 91
4 3 68
5 3 55

Log dostępu serwera WWW też jest rozdzielony spacjami, więc pola wybierasz tak samo. Numery pól pierwszego wiersza testowego logu wyglądają tak.

PoleWartość w pierwszym wierszuZnaczenie
$1192.0.2.10IP klienta
$4[29/Oct/2026:00:01:12Data i godzina żądania
$6"GETMetoda żądania (z cudzysłowem na początku)
$7/index.htmlAdres URL żądania
$9200Kod stanu
$105120Wysłane bajty
$11"-"Poprzednia strona (Referer)
$12~$15"Mozilla/5.0 (X11; Linux x86_64)"User agent (dzielony przy każdej spacji)

Wypisano $1, $7 i $9, czyli IP klienta, adres URL żądania i kod stanu.

awk '{print $1, $7, $9}' access.log
192.0.2.10 /index.html 200
198.51.100.7 /about.html 200
192.0.2.10 /images/logo.png 200
203.0.113.25 /wp-login.php 404
203.0.113.25 /wp-login.php 404
192.0.2.10 /contact.html 200
198.51.100.7 /old-page.html 301
203.0.113.25 /.env 404
192.0.2.44 /index.html 200
198.51.100.7 /api/search?q=awk 500
192.0.2.44 /images/logo.png 304
192.0.2.10 /index.html 200

Kolumna ze spacjami w wartości, taka jak user agent, dzieli się na kilka pól. NF we wszystkich trzech pierwszych wierszach wyniosło 15, a $NF to ostatni fragment user agenta.

awk '{print NF, $NF}' access.log | head -3
15 x86_64)"
15 x86_64)"
15 x86_64)"

2️⃣ Ustawianie separatora przez awk -F

  • ↪️ Separatory: dwukropek, przecinek i wyrażenie regularne

W pliku, którego kolumny rozdziela inny znak niż spacja, wpisz ten znak po -F. Po wypisaniu $1 bez -F z listy kont users.txt, przygotowanej w tej samej postaci co /etc/passwd, większość wierszy pojawiła się w całości.

awk '{print $1}' users.txt
root:x:0:0:root:/root:/bin/bash
bin:x:1:1:bin:/bin:/sbin/nologin
daemon:x:2:2:daemon:/sbin:/sbin/nologin
nobody:x:65534:65534:Kernel
user:x:1000:1000:Example
deploy:x:1001:1001:Deploy
backup:x:1002:1002::/home/backup:/sbin/nologin

Domyślnym separatorem jest spacja, więc wiersz połączony tylko dwukropkami ma jedno pole. Tylko wiersze nobody, user i deploy, które mają spację w kolumnie opisu, są przy niej ucinane.

Z -F: dwukropek staje się separatorem, a nazwa konta ($1) i powłoka logowania ($7) rozdzielają się.

awk -F: '{print $1, $7}' users.txt
root /bin/bash
bin /sbin/nologin
daemon /sbin/nologin
nobody /sbin/nologin
user /bin/bash
deploy /bin/bash
backup /sbin/nologin

Pliki CSV rozdzielone przecinkami dzielisz przez -F,. Po wypisaniu towaru i ilości z zapisów sprzedaży sales.csv nagłówek w pierwszym wierszu (item qty) też dzieli się tak samo i pojawia się razem z nimi.

awk -F, '{print $2, $3}' sales.csv
item qty
keyboard 2
mouse 5
monitor 1
keyboard 1
cable 10
mouse 2
monitor 2

-F, nie nadaje się do plików CSV z przecinkami w kolumnach ujętych w cudzysłów. W quoted.csv, z przecinkami w kolumnie towaru, pola dzielą się także przy przecinkach w cudzysłowie, a w drugim polu zostaje tylko początek nazwy towaru.

awk -F, '{print $2}' quoted.csv
item
"cable
keyboard

Dla takich plików oficjalny podręcznik GNU Awk opisuje zmienną FPAT. Jeśli zamiast separatora zapiszesz kształt jednego pola wyrażeniem regularnym, kolumna w cudzysłowie stanie się jednym polem.

awk -v FPAT='([^,]*)|("[^"]*")' '{print $2}' quoted.csv
item
"cable, usb"
keyboard

Aby użyć kilku separatorów, zapisz je jako wyrażenie regularne w nawiasach kwadratowych. Gdy separatorami są dwukropek i ukośnik, $NF staje się ostatnią nazwą w ścieżce powłoki logowania (bash, nologin).

awk -F'[:/]' '{print $1, $NF}' users.txt
root bash
bin nologin
daemon nologin
nobody nologin
user bash
deploy bash
backup nologin

3️⃣ Wzorce warunkowe polecenia awk

  • ↪️ Wyrażenia regularne, porównania i NR

Nawet po wybraniu pól wypisywane są wszystkie wiersze, więc aby zostawić tylko potrzebne, umieść warunek (wzorzec) przed nawiasami klamrowymi. Ciąg znaków między ukośnikami wybiera tylko wiersze, które go zawierają, a po pominięciu akcji wypisywany jest cały wiersz.

awk '/wp-login/' access.log
203.0.113.25 - - [29/Oct/2026:00:04:51 +0000] "POST /wp-login.php HTTP/1.1" 404 196 "-" "Mozilla/5.0 (X11; Linux x86_64)"
203.0.113.25 - - [29/Oct/2026:00:04:52 +0000] "POST /wp-login.php HTTP/1.1" 404 196 "-" "Mozilla/5.0 (X11; Linux x86_64)"

Wybrane wiersze są takie same jak w poleceniu grep, a awk od razu wybiera z nich pola i je wypisuje. Po przekazaniu potokiem do awk tych samych dwóch wierszy wybranych przez grep zostają tylko IP i kod stanu.

grep wp-login access.log | awk '{print $1, $9}'
203.0.113.25 404
203.0.113.25 404

Wartości pól porównujesz przez ==, !=, >, >=, <, <=. Wybrano tylko wiersze z kodem stanu ($9) 404 i wypisano IP oraz adres URL żądania.

awk '$9 == 404 {print $1, $7}' access.log
203.0.113.25 /wp-login.php
203.0.113.25 /wp-login.php
203.0.113.25 /.env

Przy porównywaniu z ciągiem znaków ujmij wartość w cudzysłów. Wybrano tylko imiona, których drugie pole to pass.

awk '$2 == "pass" {print $1}' scores.txt
alice
carol
dave

Porównanie liczbowe służy do wybierania według zakresu, na przykład numerów kont (UID). Po wybraniu kont z UID od 1000 wzwyż obok zwykłych kont pojawia się też nobody z UID 65534.

awk -F: '$3 >= 1000 {print $1, $3}' users.txt
nobody 65534
user 1000
deploy 1001
backup 1002

Dwa warunki łączysz przez &&. Po dodaniu warunku poniżej 65534 nobody znika i zostają tylko trzy zwykłe konta oraz ich foldery domowe.

awk -F: '$3 >= 1000 && $3 < 65534 {print $1, $6}' users.txt
user /home/user
deploy /home/deploy
backup /home/backup

[~] sprawdza, czy pole pasuje do wyrażenia regularnego, a [!~], czy nie pasuje. Wybór kont, których powłoka logowania ($7) kończy się na bash, oraz kont innych niż nologin daje te same trzy konta.

awk -F: '$7 ~ /bash$/ {print $1}' users.txt
root
user
deploy
awk -F: '$7 !~ /nologin/ {print $1, $7}' users.txt
root /bin/bash
user /bin/bash
deploy /bin/bash

Warunek NR wybiera według numeru wiersza. NR > 1 usuwa wiersz nagłówka CSV i zostają tylko zapisy sprzedaży.

awk -F, 'NR > 1 {print $2, $3}' sales.csv
keyboard 2
mouse 5
monitor 1
keyboard 1
cable 10
mouse 2
monitor 2

Wyjście innych poleceń też możesz przekazać potokiem i podzielić tak samo. Po wybraniu rozmiaru pliku ($5) i nazwy ($9) z wyjścia ls -l pierwszy wiersz był pusty, bo pierwszy wiersz ls -l, [total 24], nie ma piątego i dziewiątego pola.

ls -l | awk '{print $5, $9}'

1567 access.log
79 quoted.csv
207 sales.csv
85 scores-copy.txt
85 scores.txt
315 users.txt

Po dodaniu NR > 1 pierwszy wiersz znika i zostają tylko rozmiary i nazwy plików.

ls -l | awk 'NR > 1 {print $5, $9}'
1567 access.log
79 quoted.csv
207 sales.csv
85 scores-copy.txt
85 scores.txt
315 users.txt

4️⃣ awk BEGIN, END, sumy i średnie

  • ↪️ Zmienne i formaty wyjścia printf

Blok BEGIN działa raz przed odczytaniem pierwszego wiersza, a blok END raz po przetworzeniu ostatniego. Sumę dodajesz do zmiennej w każdym wierszu i wypisujesz w END. Poniższy diagram pokazuje kolejność, jaką awk przechodzi dla każdego wiersza przy sumowaniu kwot z zapisów sprzedaży.

🔁 Kolejność, w jakiej awk przetwarza sales.csv wiersz po wierszu
Diagram objaśniający
🔁 Kolejność przetwarzania
$ awk -F, 'NR > 1 {t += $3 * $4} END {printf "total %.2f\n", t}' sales.csv
① Odczytany wierszNR = 1date,item,qty,priceNR = 22026-10-01,keyboard,2,45.00NR = 32026-10-01,mouse,5,19.90NR = 82026-10-04,monitor,2,189.00Brak dalszych wierszyWiersz 8 jest ostatni.
② Podział na pola (-F,)$1date$2item$3qty$4priceWiersz nagłówka dzieli się tak samo.$12026-10-01$2keyboard$32$445.00$3 ilość, $4 cena jednostkowa$12026-10-01$2mouse$35$419.90$3 ilość, $4 cena jednostkowa$12026-10-04$2monitor$32$4189.00$3 ilość, $4 cena jednostkowaBrak wiersza do podziałuBlok END nie czyta wierszy.
③ Wzorzec i akcjaNR > 1 fałszAkcja jest pomijana.t = (pusta wartość)NR > 1 prawdat += 2 * 45.00t = 90NR > 1 prawdat += 5 * 19.90t = 189.5NR > 1 prawdat += 2 * 189.00t = 886.3Wykonanie ENDtotal 886.30printf wypisuje t z dwoma miejscami po przecinku.
Pierwszy wiersz to nagłówek, więc NR > 1 jest fałszem i awk przechodzi do następnego wiersza bez wykonania akcji.
Od drugiego wiersza wzorzec jest prawdziwy, a 90, czyli ilość razy cena jednostkowa, dodaje się do zmiennej t.
Zmienna t zachowuje wartość między wierszami, więc suma do trzeciego wiersza to 189.5.
Wiersze od 4 do 7 przechodzą tę samą kolejność, a do ostatniego, ósmego wiersza t osiąga 886.3.
Po przetworzeniu ostatniego wiersza blok END działa raz, a printf wypisuje total 886.30.

Suma wszystkich wysłanych bajtów ($10) z logu dostępu wyniosła 41298 bajtów. Zmienna użyta po raz pierwszy zaczyna od pustej wartości (jako liczba 0), więc nie trzeba jej ustawiać na 0.

awk '{sum += $10} END {print sum}' access.log
41298

Jeśli wypiszesz sumę w akcji dla każdego wiersza, a nie w END, każdy wiersz pokaże dotychczasową sumę. Gdy przy każdym dodaniu iloczynu ilości i ceny wypiszesz numer wiersza i t, pojawi się siedem wierszy bez nagłówka, a 886.3 w ostatnim wierszu to suma całkowita.

awk -F, 'NR > 1 {t += $3 * $4; print NR, t}' sales.csv
2 90
3 189.5
4 378.5
5 423.5
6 468.5
7 508.3
8 886.3

Średnią obliczasz w END, dzieląc sumę przez liczbę wierszy. Suma pięciu wyników wyniosła 343, a średnia 68.6.

awk '{total += $3; n++} END {print total, n, total / n}' scores.txt
343 5 68.6

BEGIN służy do jednorazowego wypisania wiersza nagłówka nad wynikami. Nad towarami i kwotami (ilość × cena jednostkowa) wiersz item total pojawia się tylko raz.

awk -F, 'BEGIN {print "item", "total"} NR > 1 {print $2, $3 * $4}' sales.csv
item total
keyboard 90
mouse 99.5
monitor 189
keyboard 45
cable 45
mouse 39.8
monitor 378

Separator wyjściowy zmieniasz zmienną OFS w BEGIN. Gdy OFS to przecinek, w miejscu przecinków z print pojawia się przecinek zamiast spacji, a lista kont wychodzi w postaci CSV.

awk 'BEGIN {FS = ":"; OFS = ","} {print $1, $3, $7}' users.txt
root,0,/bin/bash
bin,1,/sbin/nologin
daemon,2,/sbin/nologin
nobody,65534,/sbin/nologin
user,1000,/bin/bash
deploy,1001,/bin/bash
backup,1002,/sbin/nologin

Do wyrównania kolumn użyj printf. %-10s to ciąg wyrównany do lewej na 10 znakach, %3d to liczba całkowita na 3 znakach, a %8.2f to liczba na 8 znakach z dwoma miejscami po przecinku.

awk -F, 'NR > 1 {printf "%-10s %8.2f\n", $2, $3, $3 * $4}' sales.csv
keyboard     2    90.00
mouse        5    99.50
monitor      1   189.00
keyboard     1    45.00
cable       10    45.00
mouse        2    39.80
monitor      2   378.00

W przeciwieństwie do print printf nie przechodzi do nowego wiersza, więc dodaj [\n] na końcu formatu. Bez [\n] nazwy towarów łączą się w jednym wierszu.

awk -F, 'NR > 1 {printf "%s ", $2}' sales.csv
keyboard mouse monitor keyboard cable mouse monitor

5️⃣ Analiza logów i opcje polecenia awk

  • ↪️ Zliczanie adresów IP i kodów stanu, podsumowanie opcji

🔲 Analiza logów

Dodawanie do jednej zmiennej daje tylko jedną sumę, więc aby liczyć osobno według IP lub kodu stanu, zbieraj wartości w tablicy. n[$1]++ dodaje 1 do elementu tablicy o kluczu IP, a for (ip in n) w END wyjmuje zebrane elementy po kolei.

awk '{n[$1]++} END {for (ip in n) print n[ip], ip}' access.log | sort -rn
4 192.0.2.10
3 203.0.113.25
3 198.51.100.7
2 192.0.2.44

Kolejność wyjmowania przez for (ip in n) nie jest określona (według podręcznika GNU Awk), dlatego posortowano według liczby żądań przez sort -rn. Najwięcej miał 192.0.2.10, 4 żądania.

Liczbę według kodu stanu zliczasz tak samo. Były 3 odpowiedzi 404 i 1 odpowiedź 500.

awk '{n[$9]++} END {for (s in n) print s, n[s]}' access.log | sort
200 6
301 1
304 1
404 3
500 1

Wyjęcie samych kodów stanu i przekazanie ich do sort i uniq -c daje te same liczby.

awk '{print $9}' access.log | sort | uniq -c
      6 200
      1 301
      1 304
      3 404
      1 500

Aby zobaczyć tylko odpowiedzi z błędem, dodaj warunek na kod stanu. Wiersze od 400 wzwyż to trzy żądania szukające wp-login.php i .env oraz jeden błąd 500.

awk '$9 >= 400 {print $9, $1, $7}' access.log
404 203.0.113.25 /wp-login.php
404 203.0.113.25 /wp-login.php
404 203.0.113.25 /.env
500 198.51.100.7 /api/search?q=awk

Sumę wysłanych bajtów na IP też liczysz w tablicy. Najwięcej otrzymał 192.0.2.10, 31340 bajtów.

awk '{b[$1] += $10} END {for (ip in b) print b[ip], ip}' access.log | sort -rn
31340 192.0.2.10
5120 192.0.2.44
4250 198.51.100.7
588 203.0.113.25

Pole czasu ($4) można porównywać jako ciąg znaków. Wśród wierszy o tej samej dacie i formacie kolejność ciągów odpowiada kolejności czasu, dlatego wybrano tylko cztery żądania od 00:05 do tuż przed 00:10.

awk '$4 >= "[29/Oct/2026:00:05" && $4 < "[29/Oct/2026:00:10" {print $4, $7}' access.log
[29/Oct/2026:00:05:30 /contact.html
[29/Oct/2026:00:07:02 /old-page.html
[29/Oct/2026:00:07:15 /.env
[29/Oct/2026:00:09:48 /index.html

🔲 Opcje polecenia awk

📌 Główne opcje: wyniki z tego artykułu

OpcjaZadanieWynik w tym artykule
-F fsUstawia separator pól wejściowych-F: rozdziela nazwę konta ($1) i powłokę logowania ($7) w users.txt, -F, wypisuje towar i ilość z sales.csv razem z nagłówkiem (item qty)
-v var=valPrzypisuje wartość zmiennej przed uruchomieniem programuPrzekazanie zmiennej powłoki min przez -v min=$min wypisuje sześć wierszy z co najmniej 1000 wysłanych bajtów, z -v FPAT=… kolumna w cudzysłowie w quoted.csv staje się jednym polem
-i inplaceZapisuje wyjście do oryginalnego pliku zamiast na ekranPo gawk -i inplace na ekranie nic się nie pojawia, a kopia scores.txt zmienia się na dwie kolumny, imię i punkty, z -v inplace::suffix=.bak poprzednia treść zostaje w pliku .bak
--versionWypisuje informacje o wersjiPierwszy wiersz [awk --version] pokazuje wersję GNU Awk 5

📎 Pozostałe opcje: według oficjalnego podręcznika

OpcjaZadanie
-f program-fileCzyta program AWK z pliku zamiast z pierwszego argumentu wiersza poleceń, -f można podać wiele razy
-e program-textUżywa tekstu z wiersza poleceń jako źródła programu AWK, można łączyć z funkcjami bibliotek wczytanymi przez -f lub --include
-E filePodobna do -f, ale przetwarzana na końcu i blokuje przypisania zmiennych w wierszu poleceń, dla skryptów #!
--traditionalDziała w trybie zgodności, nie rozpoznaje rozszerzeń GNU
--posixWłącza tryb zgodności z dodatkowymi ograniczeniami, na przykład nie rozpoznaje func, synonimu function
--lintOstrzega przed konstrukcjami wątpliwymi lub trudnymi do przeniesienia do innych implementacji AWK, przy --lint=fatal ostrzeżenia stają się błędami krytycznymi
--dump-variablesZapisuje do pliku posortowaną listę zmiennych globalnych z typami i końcowymi wartościami, bez podania pliku awkvars.out

🔲 Symulator polecenia awk

W symulatorze poniżej możesz sam wpisywać polecenia awk dla tych samych plików testowych.

Symulator polecenia awkGNU Awk 5
[root@server work]#
Mały interpreter awk działający tylko w twojej przeglądarce. Cztery pliki testowe są takie same jak przy pomiarach, a klawiszami ↑↓ przywołasz wcześniejsze polecenia.

🔢 FAQ & polecane treści

Powłoka nie zmienia $min w apostrofach, więc trafia ono do awk bez zmian i trzeba je przekazać opcją -v. Po wpisaniu 1000 do zmiennej powłoki min i przekazaniu -v min=$min pojawia się sześć wierszy z co najmniej 1000 wysłanych bajtów. Gdy ujmiesz program awk w cudzysłów, powłoka najpierw zamieni nawet $1 w [print $1] na pustą wartość i zostanie wypisany cały wiersz.

Z -i inplace GNU Awk zapisuje wyjście do oryginalnego pliku zamiast na ekran. Po uruchomieniu przez gawk -i inplace programu wypisującego pierwsze i trzecie pole na kopii scores.txt na ekranie nic się nie pojawiło, a plik zmienił się na dwie kolumny, imię i punkty. Ponieważ oryginalny plik jest od razu nadpisywany, dodanie -v inplace::suffix=.bak zostawia poprzednią treść w pliku .bak.

Na serwerze AlmaLinux 9 /usr/bin/awk był dowiązaniem symbolicznym do gawk, a pierwszy wiersz [awk --version] pokazywał wersję GNU Awk 5. Na tym serwerze obie nazwy uruchamiają ten sam program. Przed użyciem funkcji GNU Awk, takich jak -i inplace czy FPAT, sprawdź przez [awk --version], czy to GNU Awk.

ℹ️ Informacja o linkach partnerskich
Treści tej witryny zawierają linki partnerskie. Jeśli odwiedzający kupi produkt lub usługę przez taki link, witryna otrzymuje od sprzedawcy prowizję. Kwota płacona przy tym przez kupującego (podczas promocji spada↓) nie wzrasta. Podane ceny, rabaty i dostępność odnoszą się do chwili pisania i mogą różnić się od stanu faktycznego, dlatego przed zakupem sprawdź je u sprzedawcy. Produkty wybieramy i oceniamy według własnych kryteriów, a prowizja nie wpływa ani na kolejność prezentacji, ani na treść ocen.

Dodaj komentarz

Twój adres email nie zostanie opublikowany. Wymagane pola są oznaczone *

Prove your humanity: 5   +   9   =