GNU/Linux >> Znalost Linux >  >> Linux

Vytiskněte předchozí řádek, pokud je splněna podmínka

Další možnost:obrátit soubor a vytisknout další řádek, pokud podmínka odpovídá:

tac file | awk '$1 == "BB" && $2 > 1 {getline; print}' | tac

O obecnosti

Myslím, že je třeba zmínit, že nejobecnější řešení této třídy problému zahrnuje dva průchody:

  • první průchod k přidání desetinného čísla řádku ($REC) na začátek každého řádku, čímž se řádky efektivně seskupují do záznamů podle $REC
  • druhý průchod se spustí při první instanci každé nové hodnoty $REC jako hranice záznamu (resetování $CURREC), poté pokračuje v nativním AWK idiomu týkající se záznamů, které následují po odpovídajících $CURREC.

V mezisouboru je nějaká posloupnost desetinných číslic následovaná oddělovačem (z lidských důvodů obvykle přidaným tabulátorem nebo mezerou) analyzována (neboli koncepčně odstřižena) jako mimopásmová vzhledem k základnímu souboru.

Příkazový řádek vložte monstrum

I když se omezíte na příkazový řádek, je snadné zajistit, aby se přechodný soubor nikdy nedostal na disk. Stačí použít pokročilý shell, jako je ZSH (můj oblíbený), který podporuje substituci procesů:

paste <( <input.txt awk "BEGIN { R=0; N=0; } /Header pattern/ { N=1; } { R=R+N; N=0; print R; }" ) input.txt | awk -f yourscript.awk 

Udělejme tuto jednovrstvu vhodnější pro expozici:

P="/Header pattern/"
X="BEGIN { R=0; N=0; } $P { N=1; } { R=R+N; N=0; print R; }"
paste <( <input.txt awk $X ) input.txt | awk -f yourscript.awk 

Tím se spustí tři procesy:triviální vložený skript AWK paste a skript AWK, který jste opravdu chtěli spustit.

V zákulisí, <() příkazový řádek vytvoří pojmenované potrubí a předá název kanálu, který se vloží jako název jeho prvního vstupního souboru. Pro paste 's druhým vstupním souborem, dáme mu jméno našeho původního vstupního souboru (tento soubor je tedy načítán sekvenčně, paralelně, dvěma různými procesy, které mezi sebou spotřebují maximálně jeden číst z disku, pokud je vstupní soubor studený).

Kouzlo pojmenované rourou uprostřed je FIFO v paměti, které starověký Unix pravděpodobně spravoval s průměrnou velikostí asi 16 kB (přerušované pozastavení paste proces, pokud yourscript.awk proces je pomalý při vypouštění tohoto FIFO zpět dolů).

Moderní Unix tam možná vkládá větší vyrovnávací paměť, protože může, ale rozhodně to není vzácný zdroj, o který byste se měli starat, dokud nenapíšete svůj první skutečně pokročilý příkazový řádek s přesměrováním procesů po stovkách nebo tisících :-)

Další aspekty výkonu

Na moderních CPU by všechny tři tyto procesy mohly snadno zjistit, že běží na samostatných jádrech.

První dva z těchto procesů hraničí se skutečně triviálním:skript AWK s jedním vzorem a malým vedením účetnictví, vložení volané se dvěma argumenty. yourscript.awk bude těžké běžet rychleji než tyto.

Co, váš vývojový stroj nemá žádná málo zatížená jádra, která by tento vzor hlavního shell-master řešení vytvořila téměř zdarma v doméně provádění?

Cink Cink.

Ahoj?

Hej, to je pro tebe. 2018 právě zavolal a chce svůj problém zpět.

Rok 2020 je oficiálně odkladem MTV:Tak se nám to líbí, kouzelné dýmky pro nic a jádra zdarma. Nemluvě o žádném konkrétním prodejci čipů TLA, který v těchto dnech otřásá vesmírem.

Jako poslední zvážení výkonu, pokud nechcete režii analýzy skutečných čísel záznamů:

X="BEGIN { N=0; } $P { N=1; } { print N; N=0; }"

Nyní je váš mezisoubor in-FIFO anotován pouze dalšími dvěma znaky předřazenými každému řádku ('0' nebo '1' a výchozí oddělovací znak přidaný pomocí paste ), přičemž '1' označuje první řádek v záznamu.

Pojmenované FIFO

Pod kapotou se neliší od kouzelných FIFO vytvořených Unixem, když napíšete jakýkoli normální příkaz potrubí:

cat file | proc1 | proc2 | proc2 

Tři nepojmenované kanály (a celý proces věnovaný cat ani jsi nepotřeboval).

Je téměř nešťastné, že skutečně výjimečné pohodlí výchozích proudů stdin/stdout, které jsou předspravovány shellem, zakrývá realitu, že paste $magictemppipe1 $magictemppipe2 nenese v 99 % všech případů žádné další výkonnostní aspekty, o kterých by stálo za to přemýšlet.

"Použijte <() Y-kloub, Luku."

Váš instinktivní reflex směrem k přirozenému sémantickému rozkladu v problémové doméně bude tímto nesmírně těžit.

Kdyby měl někdo důvtip a pojmenoval konstrukci shellu <() jako operátor YODA na prvním místě mám podezření, že by byl do univerzální služby vtlačen minimálně před deseti lety.


Toto může být způsob:

$ awk '$1=="BB" && $2>1 {print f} {f=$1}' file
AAAAAAAAAAAAA

Vysvětlení

  • $1=="BB" && $2>1 {print f} pokud je 1. pole přesně BB a 2. pole je větší než 1 a poté vytiskněte f , uložená hodnota.
  • {f=$1} uložit aktuální řádek do f , aby byl přístupný při čtení dalšího řádku.

Linux
  1. Jak vykopat soubor z Awk?

  2. Nemůžete najít soubor k opravě na vstupním řádku 3?

  3. Awk z různých řádků?

  1. Příklady příkazů awk v Linuxu

  2. awk:příkaz nenalezen

  3. sledovat velikost souboru v linuxu

  1. Kočičí čára X do čáry Y na obrovském souboru?

  2. Tisknout dva soubory ve dvou sloupcích?

  3. Možnost odkomentování řádku v souboru