wywołanie systemowe awk z odwróconym efektem

Mam plik danych z wieloma blokami danych zawartymi między określonymi słowami kluczowymi (DATA , END). Używam awk do wyodrębnienia bloków danych do oddzielnych plików, na podstawie nazwy pliku pobranej z wymienionego bloku. Ponieważ niektóre bloki danych mają tę samą nazwę, zmieniam nazwę każdego pliku wyjściowego na rosnącą liczbę całkowitą, jeśli plik („blockname„) już istnieje:

#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 

Oczekiwano trzech plików wyjściowych blockname1, blockname2 i blockname1_1 (zwróć uwagę, jak ostatni plik ma przypisaną liczbę całkowitą)

#cat blockname1 DATA blockname1 data1 data1 END 

(pozostałe odpowiednio …)

Teraz następujący skrypt działa tak, jak chcę:

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 problem dotyczy pętli while i jego wywołanie systemowe:

Spodziewałem się, że system("test -e " file) będzie PRAWDA, gdy file istnieje i będzie FALSE, jeśli file jeszcze nie istnieje, tzn. pętla while uruchamia się tylko wtedy, gdy file jest obecny i złamać, jeśli (nowy) file jeszcze nie istnieje.

Jednak jeśli użyję system("test -e " file) (i spraw, aby była rozwlekła za pomocą print file), mam nieskończoną pętlę o tej samej nazwie z rosnącym przyrostkiem liczby całkowitej i przeciwną system("test !-e " file) daje pożądany wynik.

Więc zachowuje się dokładnie odwrotnie do tego, czego się spodziewałem.

Odpowiedź

OK, pomyślałem: problem leży w różnych definicjach tego, co jest PRAWDA i FAŁSZ, między statusem wyjścia test a while warunek pętli w awk.

Pozytywne polecenie test skutkuje kodem zakończenia 0 dla PRAWDA i ujemny w 1 dla FALSE.

Jednak w awk pętla while interpretuje 0 jako FALSE i 1 jako TRUE, więc dokładnie odwrotnie definicja.

Jako przykład:

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

nie będzie pro duce dowolnego wyjścia, podczas gdy

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

wypisze nieskończone 1 s.

Najlepsza praktyka należy zatem wyraźnie zaznaczyć w takiej kombinacji

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

lub

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

.

W moim przypadku

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

pokazuje oczekiwane zachowanie.

Odpowiedź

awk system() zwraca kod zakończenia wykonywanego polecenia – 0 dla powodzenia i! = 0 jeśli nie powodzenie. Na przykład możesz spróbować uruchomić:

v = system("date"); 

v będzie 0

jeśli uruchomisz:

v może być 127 lub wartością inną niż 0, błąd zwrócony z systemu operacyjnego, jeśli brakuje polecenia dat lub nie znaleziono go.

Odpowiedź

Jeśli rozumiem, celem jest wyodrębnienie zawartości pliku input.file do różnych plików, aby uniknąć utraty bloków o tej samej nazwie.

Jeśli tak przypadku, a jeśli katalog docelowy jest zawsze pusty przed wyodrębnieniem, to jest lepsze (i szybsze) rozwiązanie:

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

W ten sposób awk nie „Nie trzeba uruchamiać nowej powłoki N razy tylko po to, aby sprawdzić, czy plik istnieje.

Uwagi:

  • Nie ma potrzeby bloku BEGIN, ponieważ separator pól awk jest już spacja.
  • Nie ma potrzeby umieszczania "\" na końcu linii, ponieważ pojedynczy cudzysłów jest już wielowierszowy.

Komentarze

  • Cóż, mój problem lepiej rozumiał " dziwne " zachowanie warunku while. Jednak twoje rozwiązanie jest całkiem zgrabne – dziękuję, wolę to od mojej nieporęcznej rzeczy. Blok BEGIN jest pozostałością z mojego innego formatu pliku – zapomniałem, że w moim ogólnym przykładzie staje się bezużyteczny. Pomijanie odwrotnego ukośnika oszczędzi mi trochę kłopotów. Dzięki za to też. Ale jesteś bezbłędny, jeśli chodzi o zamiar ' skryptu. Czy mógłbyś wyjaśnić część n = blocks[block]++; file=block (n? "_" n: "") bardziej szczegółowo?
  • Algorytm używa jednej tablicy: blocks, która jest indeksowana według nazwy bloku. Dawny. W pierwszym przypadku "blockname1": blocks["blockname1"]. Awk znajduje ten indeks, a ponieważ nie jest ' znaleziony, zakłada "" (również uważany za zero). Teraz w awk n = var++ jest odpowiednikiem {n=var;var++}, więc n=="" i blocks["blockname1"]==1.Wreszcie file=block (n? "_" n: "") to to samo co {file=block;if(n!="") file+="_" n}.
  • Nie byłem ' Nie wiem nawet, że łańcuch jest prawidłową zmienną indeksującą, a jest to skrócona instrukcja if – bardzo pomocna, jeszcze raz dziękuję. ' jestem zasmucony, nie mogę dać Ci " zaakceptowanej odpowiedzi " tutaj: mimo mnie zamierzam przyjąć to podejście, ponieważ spełnia ono moje początkowe zadanie, nie ' nie odpowiada na powyższe pytanie (interpretacja warunku w pętli while) – byłoby to sprzeczne z moim rozumieniem tych witryn. P & System. Jednak wiele się nauczyłem – jeszcze raz dziękuję.

Dodaj komentarz

Twój adres email nie zostanie opublikowany. Pola, których wypełnienie jest wymagane, są oznaczone symbolem *