Linux: Kniha kouzel, vanilková příchuť 2.14 (15. července 2022)
Veškerá moc příkazové řádky/příkazového řádku přehledně, pro začátečníky i pokročilé
17. Zpracování textových souborů
Řada 2.x vanilkové příchuti Linuxu: Knihy kouzel je od 15. července 2022
do 1. března 2025 ve stavu dlouhodobé pasivní údržby;
nahlášené chyby budou opravovány, ale aktivní vývoj se již věnuje jiným
projektům. Máte-li zájem pokračovat v tvorbě Linuxu: Knihy kouzel
pro novější verze linuxových operačních systémů,
kontaktujte autora nebo rovnou vytvořte odnož.
Tato kapitola se zabývá nástroji pro řazení, filtrování, analýzu, konverzi a jiné zpracování textových souborů.
Nezabývá se však komplexními nástroji jako GNU awk, sed či Perl, kterým budou věnovány samostatné
kapitoly.
Textové soubory se vyznačují tím, že jsou tvořeny posloupností řádek (v této kapitole zvaných „záznamy“)
tvořených řetězci znaků z tzv. znakové sady. V souboru jsou znaky uloženy ve formě jednobajtových
či vícebajtových sekvencí, jejichž význam určuje použité kódování znaků (v dnešní praxi téměř výhradně
UTF-8 nebo jeho podmnožina ASCII).
Většina nástrojů používaných v této kapitole je vyvíjena v rámci projektu GNU.
Kódování znaků (character encoding) je určitá reprezentace znakové sady textu pomocí bajtů a jejich sekvencí v souboru či paměti. U textových souborů uvažujeme výhradně kódování UTF-8, případně jeho podmnožinu ASCII. Soubory v jiných kódováních sice také můžeme zpracovávat, ale obvykle je výhodnější je nejprve převést na UTF-8.
Znak (character) je základní jednotka textu, které je kódováním znaků přiřazen nějaký význam a binární reprezentace. Např. „A“ je v UTF-8 znak, který znamená písmeno A a je reprezentován bajtem o hodnotě 65. „\n“ je v UTF-8 znak, který znamená konec řádku a je reprezentován bajtem o hodnotě 10.
Řetězec (string) je libovolná posloupnost znaků, i prázdná či tvořená jedním znakem.
Záznam je zobecnění pojmu „řádka“ v textovém souboru. Textový soubor se dělí na jednotlivé záznamy podle jejich zakončení ukončovačem záznamu (record separator), což je typicky znak konce řádky „\n“ nebo nulový bajt „\0“. Záznamy se číslují od 1.
Záznam může být brán jako celek, nebo může být dál dělen na sloupce (fields). Existuje několik metod dělení záznamu na sloupce, nejčastější je použití určitého znaku ASCII jako „oddělovače sloupců“ (field separator). Sloupce se v každém záznamu číslují od 1.
Záplata je speciální textový soubor, který obsahuje záznam o změnách mezi dvěma verzemi jednoho nebo více textových souborů. Využití záplat je v dnešní době zřídkavé.
V této kapitole rozlišuji následující formáty textových souborů:
TXT – záznamy ukončeny „\n“, na sloupce se nedělí.
TXTZ – záznamy ukončeny „\0“, na sloupce se nedělí.
TSV – záznamy ukončeny „\n“, sloupce se dělí tabulátorem („\t“) nebo jiným znakem ASCII (např. v /etc/passwd se dělí znakem „:“).
TSVZ – záznamy ukončeny „\0“, sloupce se oddělují tabulátorem („\t“) nebo jiným znakem ASCII.
pevná šířka sloupců – záznamy ukončeny „\n“, sloupce (kromě posledního) jsou zarovnány na pevný počet znaků pomocí mezer.
Důležitá poznámka pro všechna zaklínadla v této sekci: Kde je v zaklínadle volitelný parametr „z“ (resp. „-z“), tento parametr funguje jako přepínač mezi formáty txt a txtz. Při použití formátu txt tento přepínač vynechejte, při použití txtz ho naopak vždy zařaďte.
Důležité poznámka pro všechna zaklínadla v této sekci: Kde je v zaklínadle volitelný parametr „z“ (resp. „-z“), tento parametr funguje jako přepínač mezi formáty tsv a tsvz. Při použití formátu tsv tento přepínač vynechejte, při použití tsvz ho naopak vždy zařaďte.
Nastaví oddělovač sloupců pro parametr -f; výchozí je "\t", což znamená tabulátor. Používejte pouze znaky ASCII.
○ -f sloupce ○ -b bajty
Definuje množinu sloupců či bajtů každého záznamu, které mají být propuštěny. Pozor, pořadí ani duplicity nemají vliv na výstup! Příklad specifikace: „7,13-15,-3,20-“
☐ --complement
Neguje definovanou množinu – vybrané sloupce či bajty vypustí a vezme zbytek.
Definuje oddělovač sloupců. Prázdný argument značí, že se soubory na sloupce nedělí.
○ -a 1-nebo-2 ○ -v 1-nebo-2
Dovolí vypsání nespárovaných záznamů ze souboru 1 nebo 2. Varianta „-v“ navíc potlačí vypsání spárovaných záznamů.
☐ -o formát
Definuje pořadí sloupců na výstupu. Jednotlivé specifikace mohou mít tvar „0“ (společný sloupec), „1.číslo“ pro sloupec prvního souboru nebo „2.číslo“ pro sloupec druhého souboru. Specifikace se oddělují čárkami nebo mezerami. Příklad specifikace: „0,1.1,1.2,2.1,2.2,0“.
☐ -z
Ukončovač záznamu je \0 místo \n.
○ --check-order ○ --nocheck-order
Zapne, resp. vypne kontrolu uspořádání vstupního souboru.
Definuje znaky vkládané v místech spojení záznamů. Je-li předaný řetězec prázdný, použijí se prázdné řetězce, jinak se budou cyklicky používat jednotlivé znaky ze zadaného řetězce.
☐ -z
Ukončovač záznamu je \0 místo \n.
☐ -s
Ukončovače záznamu kromě posledního interpretuje jako oddělovače sloupců, tím pádem spojí všechny záznamy do jednoho.
Definuje řadicí klíč, podle kterého se má řadit. Podrobněji – viz manuálová stránka příkazu sort.
☐ -t oddělovač
Definuje oddělovač polí při řazení podle klíčů.
☐ -m
Místo řazení pouze slučuje již seřazené soubory do jednoho.
☐ -s
Stabilní řazení. Zachová relativní pořadí řádků, jejichž všechny řadicí klíče se rovnají.
○ -druh-řazení
Přepne na jiný druh řazení než obyčejné řetězcové.
☐ -příznak-řazení
Nastaví příslušný příznak ovlivňující řazení.
Druhy řazení jsou: g, h, M, n, R, V. Za zmínku z nich stojí jen „n“ – řazení podle číselné hodnoty (včetně případných desetinných míst) a „h“ – totéž, ale s rozpoznáváním přípon K (kilo), M (mega) atd.
Příznaky řazení jsou tyto:
r
Řadit sestupně (normálně se řadí vzestupně).
f
Nerozlišovat velká a malá písmena.
d
„Řazení jako ve slovníku“ – zohledňovat jen písmena, čísla a bílé znaky.
b
Ignorovat bílé znaky na začátku klíče (při řazení podle číselné hodnoty se ignorují vždy).
Nastavení „LC_ALL=C“ zapíná řazení po bajtech podle jejich číselné hodnoty. Je rychlé, spolehlivé a dokonale přenositelné, nejde však o řazení pro člověka.
Pozor, „sort -k 2“ znamená řadit podle sloupců 2, 3, 4 atd. až do konce; řazení podle sloupce číslo 2 je „sort -k 2,2“!
Řazení podle klíčů může být pro začátečníka záludné. Doporučuji zvolený klíč nejprve otestovat na krátkém vstupním souboru s parametrem „--debug“.
5 Poznámka: V hledaném podřetězci se nesmí vyskytovat znak \n, a to ani u formátu txtz, protože fgrep tento znak používá k oddělení více různých hledaných podřetězců. Pokud váš podřetězec tento znak obsahuje, existuje několik řešení, nejjednodušším je pomocí příkazu „tr“ na vstupu i výstupu příkazu fgrep prohodit znak \n s jiným ASCII znakem, který se v hledaném podřetězci nevyskytuje.
6 Znaky „/“ v regulárním výrazu je nutno odzvláštnit zpětným lomítkem (popř. GNU sed umožňuje použít jiný oddělovač regulárního výrazu).
7 Tip: nejlepšího výkonu této varianty dosáhnete tak, že začnete od nejmenšího vstupního souboru.
8 Standardní vstup můžete mezi soubory vřadit parametrem „-“ místo názvu souboru. Neprázdné soubory musejí být řádně ukončeny ukončovačem záznamu, jinak se poslední záznam spojí s prvním záznamem následujícího souboru.
9 Přípona výstupních souborů nesmí obsahovat oddělovač adresářů „/“. Číslování výstupních souborů začíná od nuly; jinou hodnotu lze nastavit, když místo parametru -d použijete parametr --numeric-suffixes=číslo. Uvedený příklad rozdělí soubor „vse.txt“ po sto řádcích na soubory „rozdelene-zaznamy/s00000dil.txt“, „rozdelene-zaznamy/s00001dil.txt“ atd.
10 Příkaz „sed“ vyžaduje v příponě i předponě další úroveň odzvláštnění znaků „\“ a „\n“. Proto v uvedeném případě zadávejte zpětné lomítko jako „\\\\“ a konec řádky jako „\\\n“. Konec řádky se navíc může vyskytnout pouze při použití formátu txtz, u formátu txt pravděpodobně nebude fungovat správně.
11 Uvedené varianty se liší požadavky na odzvláštnění v příponě: v první variantě sed požaduje dodatečné odzvláštění znaků „\“ a (případně) konce řádku; v druhé variantě požaduje sed odzvláštnění znaků „\“, „/“ a „&“.
12 Běžně se k tomu používá příkaz „fmt“, ale ten nerespektuje vícebajtové znaky, takže pro texty v UTF-8 funguje nekorektně.
13 Specifikace sloupců specifikuje množinu (tzn. ne výčet) sloupců. Má tvar jednotlivých čísel oddělených čárkami, např. „7,3,2,5,2“ vypíše sloupce 2, 3, 5 a 7. Místo jednotlivého čísla lze zadat rozsah ve tvaru „číslo-číslo“, „číslo-“ nebo „-číslo“, který se rozvine na všechny odpovídající sloupce, takže např. specifikace „7,3-5,-4“ odpovídá sloupcům 1, 2, 3, 4, 5 a 7.
14 Pro čtení ze standarního vstupu zadejte místo souboru „-“.
15 Chování příkazu „join“ je smysluplné, ale poměrně komplikované. Před použitím tohoto zaklínadla prosím nastudujte manuálovou stránku příkazu join!
16 Poznámka: prázdný řádek se počítá jako 0 sloupců, proto pokud ho vstup obsahuje, výsledek bude 0.
17 Poznámka: zadáte-li víc souborů, počítadlo záznamů se nebude restartovat na začátku každého z nich.
18 Pro podrobnější popis syntaxe vyhledejte kapitolu Sed!
19 Počet „původních“ a „náhradních“ znaků musí přesně odpovídat. Znaky „/“ a „\“ je v obou výčtech nutno odzvláštnit dalším zpětným lomítkem. Na místo znaku můžete použít i sekvenci „\0“, „\n“ apod. „Náhradní znaky“ se smí opakovat, „původní“ ne.
20 Pro složitější případy je v GNU awk funkce „substr()“ nebo zvláštní režim pro zpracování souborů s pevnou šířkou sloupců.
21 Aby záplata fungovala, označení starého a nového adresáře nesmějí obsahovat žádná lomítka, musejí to být jen holá jména podadresářů aktuálního adresáře.
Líbí se vám tento projekt a chcete, aby byl ještě lepší? Můžete mi s tím pomoci. Zmiňte se o něm technicky zdatným přátelům, opravte překlepy a nahlašte nefunkční zaklínadla, aby mohla být opravena; poskytněte mi zpětnou vazbu nebo se zapojte do vývoje nových kapitol. Další informace na GitHubu v dokumentu Jak se zapojit.