2011-06-23 18 views
7

Mam duży plik z setkami kolumn, z których chcę usunąć tylko trzecią i czwartą kolumnę i wydrukować resztę do pliku. Moim początkowym pomysłem było utworzenie skryptu awk, takiego jak awk '{print $1, $2, for (i=$5; i <= NF; i++) print $i }' file > outfile. Jednak ten kod nie działa.wydrukuj wszystkie, ale wybierz pola w awk

Następnie próbowałem:

awk '{for(i = 1; i<=NF; i++) 
if(i == 3 || i == 4) continue 
else 
print($i)}' file > outfile 

ale to tylko drukowany wszystko w jednym polu. Byłoby możliwe podzielenie tego na dwa skrypty i połączenie ich z Uniksem paste, ale wydaje się, że to coś, co powinno być możliwe do zrobienia w jednym wierszu.

+0

Mam kilka funkcji filtrowania kolumny awk tutaj, jeśli jesteś zainteresowany https://github.com/mhitza/inflated-shell/blob/master/ src/filters/input/column – mhitza

Odpowiedz

9

Twoja pierwsza próba była całkiem blisko. Modyfikowanie go używać printf włącznie separatory pól pracował dla mnie:

awk '{printf $1FS$2; for (i=5; i <= NF; i++) printf FS$i; print NL }' 
+0

+1 Nie wiedziałem o 'NL' zamiast tego zawsze używanym' '\ n" '. – mhitza

+1

NL nie jest standardową funkcją awk (ani nawet niestandardową w żadnej z 4 implementacji, do których mam dostęp). To tylko zwykła zmienna, tutaj niezainicjowana. 'Print NL' kończy drukowanie znaku nowej linii, ponieważ interpretuje się go jako' print '". 'print sjskjsdsj' miałby taki sam rezultat. – dubiousjim

0

Jak o właśnie ustawienie trzeciej i czwartej kolumnie na pusty ciąg znaków:

echo 1 2 3 4 5 6 7 8 9 10 | 
awk -F" " '{ $3=""; $4=""; print}' 
+3

Ale nadal utkniesz z ogranicznikami: 'echo 1: 2: 3: 4: 5: 6: 7: 8: 9: 10 | awk-F: 'BEGIN {OFS = FS} {$ 3 = ""; 4 USD = ""; print} '' –

6

że masz kartę ograniczony plik, który wygląda tak:

temp.txt

pole1 pole2 field3 Field4 dziedzinie5 field6
pole1 pole2 field3 Field4 dziedzinie5 field6
pole1 pole2 field3 Field4 dziedzinie5 field6

uruchomienie następuje usunięcie pola 3 i 4, a wyjście do końca linii.

awk '{print $1"\t"$2"\t"substr($0, index($0,$5))}' temp.txt

pole1 pole2 dziedzinie5 field6
pole1 pole2 dziedzinie5 field6
pole1 pole2 dziedzinie5 field6

moim przykładzie (S) wydrukować na standardowe wyjście. > newFile wyśle ​​stdout do newFile i >> newFile zostanie dołączony do newFile.

Więc może chcesz użyć następujących:

awk '{print $1"\t"$2"\t"substr($0, index($0,$5))}' temp.txt > newFile.txt

niektórzy opowiadają się za cięcie

cut -f1,2,5- temp.txt

które wytwarzają taką samą moc, a cięcie jest świetny dla uproszczenia, ale nie obsługuje niespójnych ograniczników. Na przykład mieszanka różnych białych znaków. Jednak w tym przypadku cięcie może być tym, o co prosisz.

można to również zrobić w perlu, python, ruby ​​i wielu innych, ale tutaj jest najprostsze rozwiązanie awk.

+0

awk działa, dopóki zawartość pola 5 nie znajdzie się w jednym z czterech pierwszych pól. W tym przypadku zbyt szybko Ci się uda. – NeronLeVelu

6

Co o czymś takim:

cat SOURCEFILE | cut -f1-2,5- >> DESTFILE 

Drukuje pierwsze dwie kolumny, pomija 3. i 4rth, a następnie drukuje od 5 roku do końca.

+0

nie trzeba go drążyć od kota. Zobacz moją odpowiedź: http://stackoverflow.com/questions/6458414/print-all-but-select-fields-in-awk/6458705#6458705 – matchew

+0

To jest dokładnie właściwa odpowiedź, dzięki! Mam na myśli, że nie używa 'awk', jak wymaga tego pytanie, ale' cut' jest doskonałym narzędziem do wykonania dokładnie tego zadania. – Thismatters

0

Tak, można ustawić trzecią i czwartą kolumnę w pustym ciągu; ale dodatkowo pole $1 powinno być ustawione na siebie ($1=$1), aby awk rzeczywiście zużyło separator pola wejściowego (ogranicznik) : na całej bieżącej linii $0 za jednym razem.

echo 1:2:3:4:5:6:7:8:9:10 | awk -F: '{ $1=$1; $3=""; $4=""; print $0}' 
0

Twardy ale rodzajowy sposób (zapomnieć o prostym oneliner)

awk -v "Exclude=3:4:5" ' 
    # load exclusion 
    BEGIN{ 
     Count=split(Exclude, aTmp, ":") 
     for(i = 1; i <= Count; i++) aExc[ aTmp[ i]]=1 
     } 

    # treat each line, taking only wanted field 
    { 
    Result="" 
    for(i = 1; i <= NF; i++) { 
     # field to take ? 
     if(! aExc[ i]) { 
     # first element or add a separator before 
     if(Result != "") Result=Result OFS $i 
      else Result=$i 
     } 
     } 

    print Result 
    }' YourFile 
  • można określić dowolne pole, które chcesz wykluczyć
    • indeks pola wypełnić varaible Wyklucz oddzielnie przez : w pierwszej linii
  • separator są poprawne wprowadzają ilość
  • kod jest „rozszerzony” dla lepszego zrozumienia
  • ostateczny wynik nie jest dokładnie tak, jak wejście (bez pola wyłączone), ponieważ separator wyjściowy jest używany zamiast oryginalnego separatora (ex 2 spacja lub karta jest zmieniana na 1 spację z domyślnym zachowaniem)