awk system call with inverted effect

Mám datový soubor s více datovými bloky uzavřenými mezi konkrétními klíčovými slovy (DATA , END). Pomocí awk extrahuji datové bloky do samostatných souborů na základě názvu souboru převzatého z uvedeného bloku. Jelikož některé datové bloky sdílejí stejný název, přejmenovávám každý výstupní soubor s rostoucím celým číslem, pokud soubor („blockname„) již existuje:

#cat input.file useless stuff1 DATA blockname1 data1 data1 END useless stuff2 DATA blockname2 data2 data2 END useless stuff3 DATA blockname1 data3 data3 END useless stuff4 

Očekávají se tři výstupní soubory blockname1, blockname2 a blockname1_1 (všimněte si, jak má poslední soubor přiřazeno celé číslo)

#cat blockname1 DATA blockname1 data1 data1 END 

(ostatní odpovídajícím způsobem …)

Nyní následující skript funguje tak, jak chci:

awk "BEGIN { FS=" +" } ; \ /DATA/,/END/ \ { if ( $1 ~ /DATA/ ) \ { block=$2 ; i=0 ; file=block ;\ while ( system("test ! -e " file ) ) \ { i++ ; file=block"_"i ; print file } \ } ; \ print $0 > file \ } " \ input.file 

Můj problém spočívá ve smyčce while a jeho systémové volání:

Očekával jsem, že system("test -e " file) bude TRUE, když file bude existovat a že bude NEPRAVDA, pokud file dosud neexistuje, tj. smyčka while se spustí, pouze pokud je file přítomna a rozbít, pokud (nový) file dosud neexistuje.

Pokud však použiji system("test -e " file) (a učiním to podrobným s print file), mám nekonečnou smyčku se stejným názvem se zvětšující se celočíselnou příponou a opačným system("test !-e " file) dává požadovaný výsledek.

Takže toto se chová přesně opačně, než jsem očekával.

Odpovědět

OK, napadlo mě: problém spočívá v různých definicích toho, co je PRAVDA a NEPRAVDA mezi stavem ukončení test a while podmínka smyčky v awk.

Výsledkem postivního test kódu ukončení je 0 pro TRUE a záporný pro 1 pro FALSE.

Avšak v awk smyčka while interpretuje 0 jako FALSE a 1 jako TRUE, takže přesně naopak definice.

Jako příklad:

awk "{ while ( 0 ) ; { print "0" } }" file 

nebude pro zkuste jakýkoli výstup, zatímco

awk "{ while (1) ; { print "1" } }" file 

vytiskne nekonečné 1 s.

Osvědčené postupy je tedy explicitní v takové kombinaci

while ( system("command") == 0 ) 

nebo

while ( system("command") == 1 ) 

.

Takže v mém případě

while ( system("test -e " file ) == 0 ) 

ukazuje očekávané chování.

Odpověď

awk system() vrátí stav ukončení spuštěného příkazu – 0 pro úspěch a! = 0, pokud ne úspěch. Pro jednoduchý příklad můžete zkusit spustit:

v = system("date"); 

v bude 0, pokud spustíte:

v = system("dat"); 

v může být 127 nebo hodnota odlišná od 0, chyba vrácená z OS, pokud příkaz dat chybí nebo nebyl nalezen.

Odpověď

Pokud vám rozumím, cílem je extrahovat obsah souboru input.file do různých souborů, aby nedocházelo ke ztrátě bloků se stejným názvem.

Pokud je to case, a pokud je cílový adresář před extrakcí vždy prázdný, existuje lepší (a rychlejší) řešení:

awk " /DATA/{ block=$2; n = blocks[block]++; file=block (n? "_" n: ""); } /DATA/,/END/{ print > file }" input.file 

Tímto způsobem awk doesn Není potřeba spustit nový shell N krát, jen aby se otestovalo, zda soubor existuje.

Poznámky:

  • Blok ZAČÍT není potřeba, protože oddělovač polí awk je již mezery.
  • Na konci řádků není třeba "\", protože jednoduchá nabídka je již víceřádková.

Komentáře

  • No, můj problém více chápal " zvláštní " chování podmínky while. Vaše řešení je však docela úhledné – děkuji, dávám přednost, toto přes mou objemnou věc. BEGIN blok je pozůstatek z mého jiného formátu souboru – zapomněl jsem, že se v mém obecném příkladu stane zbytečným. Vynechání zpětného lomítka mi ušetří nějaké potíže. Díky za to taky. Ale jste na místě ohledně záměru skriptu '. Můžete vysvětlit část n = blocks[block]++; file=block (n? "_" n: "") podrobněji?
  • Algoritmus používá jedno pole: blocks, které je indexováno podle názvu bloku. Př. V první instanci "blockname1": blocks["blockname1"]. Zdá se, že tento index našel, a protože není nalezen, předpokládá "" (také považován za nulu). Nyní je v awk n = var++ ekvivalent {n=var;var++}, takže n=="" a blocks["blockname1"]==1.Nakonec je file=block (n? "_" n: "") stejný jako {file=block;if(n!="") file+="_" n}.
  • Nebyl jsem ' I když si uvědomujete, že řetězec je platná indexovací proměnná a je toto snížené if-prohlášení – velmi užitečné, ještě jednou díky. Jsem ' m smutný, že vám nemohu dát " přijatou odpověď " zde: navzdory mně přijmeme tento přístup, protože splňuje můj původní úkol, neodpovídá ' na výše uvedenou otázku (výklad podmínky ve smyčce while) – šlo by to proti mému chápání těchto stránek Q & Systém. Přesto jsem se toho hodně naučil – ještě jednou díky.

Napsat komentář

Vaše e-mailová adresa nebude zveřejněna. Vyžadované informace jsou označeny *