0Pricing
DevOps Bootcamp · Lekcja

Rekordy, pola i niestandardowe separatory w awk

Naucz się sterować separatorami pól wejściowych i wyjściowych, aby dzielić wiersze CSV, TSV i logów na przejrzyste kolumny.

Rekordy, pola i niestandardowe separatory w awk to bezpłatna lekcja DevOps Bootcamp na CoddyKit. To lekcja 1 z 4. Możesz przeczytać całą lekcję poniżej za darmo — a potem ćwiczyć ją interaktywnie w przeglądarce z wbudowanym edytorem kodu i tutorem AI dostępnym 24/7. To część ścieżki edukacyjnej DevOps Bootcamp, a Twój postęp synchronizuje się między webem a aplikacją CoddyKit. Kurs DevOps Bootcamp zawiera 4 lekcji w sumie.

Czym są rekordy i pola w awk

awk odczytuje dane wejściowe wiersz po wierszu. Każdy wiersz nazywa się rekordem, a każdy oddzielony białymi znakami fragment tego wiersza nazywa się polem.

  • $0 — cały bieżący rekord (pełny wiersz)
  • $1 — pierwsze pole
  • $2 — drugie pole
  • $NF — ostatnie pole (NF = liczba pól)

Domyślnie awk rozdziela pola przy każdym ciągu białych znaków (spacji lub tabulatorów). Dzięki temu od razu nadaje się do analizowania logów, wyników poleceń i danych rozdzielanych spacjami.

#!/usr/bin/env bash
# Show how awk sees records and fields
echo 'alice 30 engineer' | awk '{ print "Name:", $1, "Age:", $2, "Role:", $3 }'

# $NF is always the last field — regardless of how many there are
echo 'one two three four five' | awk '{ print "Last field:", $NF }'

Separator pól wejściowych: FS

Wbudowana zmienna FS (Field Separator) informuje awk, jak dzielić każdy rekord na pola. Jej wartością domyślną jest pojedyncza spacja, która uruchamia tryb dzielenia według białych znaków.

Wartość FS można ustawić na dwa sposoby:

  • Za pomocą flagi -F w wierszu poleceń: awk -F':'
  • W bloku BEGIN: BEGIN { FS = ":" }

Oba sposoby są równoważne. Podejście z blokiem BEGIN jest preferowane w dłuższych skryptach, ponieważ przechowuje konfigurację w samym skrypcie, dzięki czemu kod jest czytelniejszy i bardziej przenośny.

#!/usr/bin/env bash
# Parse /etc/passwd using ':' as the field separator
# Field 1 = username, field 3 = UID, field 7 = shell
echo 'root:x:0:0:root:/root:/bin/bash
daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
nobody:x:65534:65534:nobody:/nonexistent:/usr/sbin/nologin' \
  | awk -F':' '{ print $1, "UID="$3, "shell="$7 }'

Ustawianie FS w bloku BEGIN

W skryptach dłuższych niż jednolinijkowe umieszczanie FS w bloku BEGIN jest standardową praktyką. Blok BEGIN jest wykonywany przed odczytaniem jakichkolwiek danych wejściowych przez awk, więc separator jest gotowy dla pierwszego rekordu.

Ten wzorzec pozwala również ustawić wiele zmiennych jednocześnie, dodawać komentarze i przechowywać całą logikę w jednym pliku skryptu.

Typowe separatory spotykane w praktyce:

  • Dwukropek : — /etc/passwd, /etc/shadow
  • Tabulator \t — eksporty TSV, dane wyjściowe kompilatorów
  • Przecinek , — pliki CSV (proste, bez pól w cudzysłowach)
  • Pionowa kreska | — niektóre formaty logów, zrzuty baz danych
#!/usr/bin/env bash
# awk script using BEGIN to set FS for TSV input
printf 'alice\t30\tengineer\nbob\t25\tdesigner\ncarol\t35\tmanager\n' \
  | awk 'BEGIN { FS = "\t" } { printf "%-10s age=%-3s role=%s\n", $1, $2, $3 }'

Analizowanie plików CSV za pomocą awk

CSV (wartości rozdzielane przecinkami) to jeden z najczęściej używanych formatów danych w inżynierii skryptów powłoki. Ustawienie FS="," pozwala traktować awk przecinki jako delimitery.

Ważne zastrzeżenie: wbudowana obsługa CSV w awk nie uwzględnia pól w cudzysłowach zawierających przecinki (np. "Smith, John"). W przypadku prostych plików CSV bez przecinków w cudzysłowach działa to bez zarzutu. Dla plików CSV zgodnych z RFC 4180, zawierających pola w cudzysłowach, należy użyć właściwego parsera CSV albo narzędzi miller/csvkit.

Typowym zadaniem w praktyce jest wyodrębnianie określonych kolumn i filtrowanie wierszy według wartości — po ustawieniu FS oba działania są w awk banalnie proste.

#!/usr/bin/env bash
# Simple CSV: extract name and salary columns, filter salary > 50000
data='name,department,salary
alice,engineering,95000
bob,marketing,48000
carol,engineering,112000
dave,hr,45000'

echo "$data" | awk -F',' '
  NR == 1 { next }          # skip header row
  $3 > 50000 { print $1, "earns", $3 }
'

Separatory pól wieloznakowe i oparte na wyrażeniach regularnych

Wartość FS w awk nie musi być pojedynczym znakiem — może być wyrażeniem regularnym. Jest to szczególnie przydatne w rzeczywistych formatach logów, w których pola są oddzielone delimiterami o zmiennej długości.

Przykłady separatorów będących wyrażeniami regularnymi:

  • FS = "[,;]" — dzielenie przy przecinku lub średniku
  • FS = "[ \t]+" — dzielenie przy jednej lub większej liczbie spacji lub tabulatorów (tak samo jak domyślnie, ale jawnie)
  • FS = "::" — dzielenie przy dosłownym podwójnym dwukropku
  • FS = "\\|" — dzielenie przy znaku pionowej kreski (musi zostać poprzedzony znakiem ucieczki)

Gdy FS jest wyrażeniem regularnym, awk (gawk) traktuje je jako wzorzec, a nie dosłowny ciąg znaków.

#!/usr/bin/env bash
# Log lines with mixed delimiters: split on " | " or "::" or ","
# Here we split on one or more spaces or pipe characters
printf '2024-01-15 | ERROR | disk full | /dev/sda1\n2024-01-15 | INFO  | startup ok | main\n' \
  | awk -F' \\| ' '{ printf "date=%-12s level=%-6s msg=%s\n", $1, $2, $3 }'

# Split on multiple possible delimiters using character class
echo 'alpha,beta;gamma,delta;epsilon' \
  | awk -F'[,;]' '{ for(i=1; i<=NF; i++) print i": "$i }'

Separator pól wyjściowych: OFS

OFS (Output Field Separator) określa, co awk umieszcza między polami podczas odtwarzania rekordu za pomocą print. Domyślnie jest to pojedyncza spacja.

Najważniejsza kwestia: OFS jest wstawiany między polami tylko wtedy, gdy używa się składni z przecinkami w print lub gdy przypisuje się wartość do pola i awk ponownie tworzy $0. Jeśli w kodzie źródłowym łączy się elementy spacjami, OFS nie jest używany.

  • print $1, $2, $3 — przecinki powodują wstawienie OFS między polami
  • print $1 " " $2 — jawna spacja, OFS jest ignorowany

Częsty wzorzec: odczyt CSV, przekształcenie i zapis TSV przez ustawienie FS="," oraz OFS="\t".

#!/usr/bin/env bash
# Convert CSV to TSV using FS and OFS
data='alice,30,engineer
bob,25,designer
carol,35,manager'

echo "$data" | awk 'BEGIN { FS=","; OFS="\t" } { print $1, $2, $3 }'

echo '---'

# OFS also applies when you modify a field — awk rebuilds $0 with OFS
echo 'alice,30,engineer' | awk 'BEGIN { FS=","; OFS=" | " } { $1=$1; print $0 }'

Wymuszanie ponownego utworzenia $0 przez awk za pomocą OFS

Istnieje subtelny, ale ważny trik: przypisanie wartości do dowolnego pola (nawet przypisanie pola do niego samego, $1=$1) wymusza ponowne utworzenie $0 przez awk poprzez połączenie wszystkich pól za pomocą OFS.

Jest to idiomatyczny sposób zmiany delimiterów rekordu bez ręcznego wypisywania każdego pola:

  • Ustawienie FS na delimiter wejściowy
  • Ustawienie OFS na żądany delimiter wyjściowy
  • Wymuszenie ponownego utworzenia rekordu za pomocą $1=$1
  • Wypisanie $0

To podejście działa dla dowolnej liczby pól i pozwala uniknąć wpisywania na stałe wartości $1, $2, $3, ....

#!/usr/bin/env bash
# Reformat a pipe-delimited file to comma-separated WITHOUT listing every field
printf 'alice|30|engineer|london\nbob|25|designer|paris\ncarol|35|manager|berlin\n' \
  | awk 'BEGIN { FS="|"; OFS="," } { $1=$1; print $0 }'

# Useful when you don't know how many fields there are:
printf 'a|b|c|d|e|f|g\n1|2|3|4|5|6|7\n' \
  | awk 'BEGIN { FS="|"; OFS="\t" } { $1=$1; print $0 }'

Separator rekordów: RS

Tak jak FS rozdziela pola w obrębie rekordu, tak RS (Record Separator) określa, co rozdziela poszczególne rekordy. Domyślnie RS jest znakiem nowego wiersza, dlatego awk przetwarza po jednym wierszu naraz.

Zmiana wartości RS umożliwia zaawansowane przetwarzanie rekordów wielowierszowych:

  • RS="" — tryb akapitów: puste wiersze rozdzielają rekordy (pola mogą obejmować wiele wierszy)
  • RS=";" — podział według średników (przydatny w zrzutach SQL)
  • RS="\n" — jawnie określony znak nowego wiersza (wartość domyślna)

W trybie akapitów (RS="") FS nadal służy do rozdzielania pól w obrębie wielowierszowego rekordu, a znaki nowego wiersza wewnątrz rekordu są również automatycznie traktowane jako separatory pól.

#!/usr/bin/env bash
# Paragraph mode: each blank-line-separated block is one record
# Useful for processing structured text blocks (e.g., stanzas, config sections)
data='Name: Alice
Role: Engineer
City: London

Name: Bob
Role: Designer
City: Paris'

echo "$data" | awk 'BEGIN { RS=""; FS="\n" } {
  print "Record", NR":"
  for (i=1; i<=NF; i++) print "  ", $i
  print ""
}'

Separator rekordów wyjściowych: ORS

ORS (Output Record Separator) jest wypisywany po każdej instrukcji print. Domyślnie jest to znak nowego wiersza (\n), dlatego każde wywołanie print rozpoczyna nowy wiersz.

Zmiana wartości ORS pozwala:

  • łączyć rekordy w jednym wierszu: ORS=" "
  • dodawać puste wiersze między rekordami wyjściowymi: ORS="\n\n"
  • tworzyć niestandardowe formaty wyjściowe, takie jak fragmenty JSON lub XML

Należy pamiętać, że printf nie używa ORS — ta zmienna dotyczy wyłącznie zwykłej instrukcji print. Z printf należy korzystać, gdy potrzebna jest pełna kontrola nad formatowaniem.

#!/usr/bin/env bash
# Join all matching lines onto one line by setting ORS to a space
printf 'apple\nbanana\ncherry\ndate\n' | awk '{ ORS=" " } { print $0 }'
echo  # final newline

# Add a blank line after every output record for readability
printf 'alice 30 engineer\nbob 25 designer\ncarol 35 manager\n' \
  | awk 'BEGIN { ORS="\n\n" } { print $1, "is a", $3 }'

Praktyczny przykład: analizowanie dzienników dostępu Apache

Dzienniki dostępu Apache/nginx mają dobrze znany format z polami rozdzielanymi spacjami. Niektóre pola (takie jak znacznik czasu) zawierają spacje i są ujmowane w nawiasy kwadratowe lub cudzysłowy — przez co bezpośredni podział na pola w awk może być kłopotliwy.

Praktycznym podejściem jest użycie wyrażenia regularnego jako FS, które uwzględnia strukturę danych, albo wyodrębnianie konkretnych pól na podstawie ich pozycji przy znajomości dokładnego formatu.

Pola formatu Combined Log Format wyglądają z grubsza tak:

  1. Adres IP klienta
  2. Ident (zwykle -)
  3. Użytkownik uwierzytelniony (zwykle -)
  4. Znacznik czasu (w nawiasach kwadratowych, liczony jako jeden token)
  5. Metoda żądania + ścieżka + protokół (w cudzysłowie)
  6. Kod statusu HTTP
  7. Liczba bajtów odpowiedzi
#!/usr/bin/env bash
# Parse a simulated Apache Combined Log Format line
# Extract: IP, status code, bytes, and request path
logs='192.168.1.10 - alice [15/Jan/2024:10:23:45 +0000] "GET /api/users HTTP/1.1" 200 1523
10.0.0.5 - - [15/Jan/2024:10:23:46 +0000] "POST /login HTTP/1.1" 401 89
172.16.0.3 - bob [15/Jan/2024:10:23:47 +0000] "GET /dashboard HTTP/1.1" 200 8741'

echo "$logs" | awk '{
  ip     = $1
  status = $9
  bytes  = $10
  # Extract the request path from the quoted string in field 7
  split($7, parts, "/")
  path = "/" parts[2]
  printf "ip=%-15s status=%s bytes=%-6s endpoint=%s\n", ip, status, bytes, path
}'

Łączenie FS, OFS, RS i ORS w potoku

W rzeczywistym tworzeniu skryptów powłoki rzadko używa się tych separatorów osobno. Częstym wzorcem potoku jest wykorzystanie awk jako konwertera formatu w środku potoku, który przekształca jeden ustrukturyzowany format w inny.

Najważniejsze zasady łączenia separatorów:

  • Zawsze ustawiaj FS i OFS razem w sekcji BEGIN podczas konwersji formatów
  • Użyj $1=$1, aby wymusić ponowne zbudowanie $0, gdy chcesz przeformatować wszystkie pola bez wymieniania ich po kolei
  • Zmieniaj RS tylko wtedy, gdy rekordy rzeczywiście obejmują wiele wierszy
  • Używaj ORS do kontrolowania odstępów między rekordami wyjściowymi
  • Wybieraj printf, gdy potrzebujesz precyzyjnego formatowania; używaj print, gdy wygodne jest automatyczne zakończenie rekordu przez ORS
#!/usr/bin/env bash
# Full pipeline: read a colon-delimited file,
# filter rows where field 3 (UID) >= 1000 (real users),
# then output as tab-separated: username, UID, home dir
echo 'root:x:0:0:root:/root:/bin/bash
daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
alice:x:1001:1001:Alice:/home/alice:/bin/bash
bob:x:1002:1002:Bob:/home/bob:/bin/zsh
www-data:x:33:33:www-data:/var/www:/usr/sbin/nologin' \
  | awk 'BEGIN { FS=":"; OFS="\t" } $3 >= 1000 { print $1, $3, $6 }'

Sprawdź wiedzę: OFS i ponowne tworzenie pól

Sprawdź swoje rozumienie tego, jak OFS współdziała z przypisywaniem pól w awk.

Podsumowanie lekcji: rekordy, pola i separatory

Masz teraz pełną kontrolę nad tym, jak awk odczytuje i zapisuje ustrukturyzowane dane. Oto podsumowanie czterech zmiennych separatorów:

  • FS — separator pól wejściowych. Ustawiany za pomocą -F lub w sekcji BEGIN. Może być znakiem, ciągiem znaków albo wyrażeniem regularnym. Wartość domyślna: białe znaki.
  • OFS — separator pól wyjściowych. Wstawiany między polami w wywołaniach print $1, $2 oraz wtedy, gdy awk ponownie tworzy $0 po przypisaniu wartości do pola. Wartość domyślna: pojedyncza spacja.
  • RS — separator rekordów wejściowych. Określa, co rozdziela rekordy (wiersze). Wartość domyślna: znak nowego wiersza. Ustawienie pustego ciągu włącza tryb akapitów.
  • ORS — separator rekordów wyjściowych. Dodawany po każdym print. Wartość domyślna: znak nowego wiersza. Można go zmienić, aby łączyć wiersze lub dodawać odstępy.

Najważniejszy wzorzec do zapamiętania: ustaw zarówno FS, jak i OFS w sekcji BEGIN, a następnie użyj $1=$1, aby ponownie zbudować $0, gdy chcesz zmienić separatory we wszystkich polach bez wpisywania pozycji pól na stałe. Ten wzorzec działa dla plików z dowolną liczbą kolumn i stanowi podstawę potoków konwersji formatów opartych na awk.

Często zadawane pytania

Czy lekcja „Rekordy, pola i niestandardowe separatory w awk” jest bezpłatna?

Tak — pełny tekst „Rekordy, pola i niestandardowe separatory w awk” jest dostępny za darmo tutaj w sieci. Aby ćwiczyć ją interaktywnie (wbudowany edytor kodu i tutor AI dostępny 24/7) i odblokować resztę kursu DevOps Bootcamp, przejdź na CoddyKit PRO. Kurs DevOps Bootcamp zawiera 4 lekcji w sumie.

Co nauczysz się w „Rekordy, pola i niestandardowe separatory w awk”?

Naucz się sterować separatorami pól wejściowych i wyjściowych, aby dzielić wiersze CSV, TSV i logów na przejrzyste kolumny. Ćwiczysz DevOps Bootcamp z praktycznym kodem, który uruchamiasz bezpośrednio w przeglądarce, a tutor AI dostępny 24/7 odpowiada na Twoje pytania podczas pracy nad lekcją.

Czy potrzebuję doświadczenia, aby zacząć DevOps Bootcamp?

Nie wymagamy żadnego doświadczenia. DevOps Bootcamp w CoddyKit jest strukturyzowany dla początkujących i zaawansowanych użytkowników, więc możesz zacząć tutaj lub od początku i uczyć się w swoim tempie. To lekcja 1 z 4.

Ile czasu zajmuje lekcja „Rekordy, pola i niestandardowe separatory w awk”?

Większość lekcji CoddyKit trwa około 5–10 minut. Każda lekcja to mały, interaktywny krok, dzięki czemu robisz systematyczne postępy i zawsze wracasz dokładnie do tego samego miejsca — na webie i w aplikacji.

Czy mogę pisać i uruchamiać kod w tej lekcji DevOps Bootcamp?

Tak. Każda lekcja DevOps Bootcamp zawiera wbudowany edytor kodu, więc piszesz i uruchamiasz prawdziwy kod bezpośrednio w przeglądarce i od razu otrzymujesz sprzężenie zwrotne od AI — bez konfiguracji na komputerze.

Wszystkie lekcje w tym kursie

  1. Rekordy, pola i niestandardowe separatory w awk
  2. Wzorce, zakresy oraz bloki BEGIN/END
  3. Agregowanie za pomocą tablic i grupowania w awk
  4. Funkcje awk, formatowanie printf i generowanie raportów
← Powrót do DevOps Bootcamp