Jak wydrukować trzecią kolumnę do ostatniej kolumny?

121

Próbuję usunąć pierwsze dwie kolumny (którymi nie jestem zainteresowany) z pliku dziennika DbgView. Nie mogę znaleźć przykładu, który drukuje od kolumny 3 do końca wiersza. Zauważ, że każda linia ma zmienną liczbę kolumn.

Amit G.
źródło
możliwy duplikat
użycia

Odpowiedzi:

108

... lub prostsze rozwiązanie: cut -f 3- INPUTFILE po prostu dodaj właściwy separator (-d) i uzyskasz ten sam efekt.

Marcin
źródło
9
Zauważ, że działa to tylko wtedy, gdy separator jest dokładnie taki sam we wszystkich kolumnach ... Na przykład nie możesz użyć wycinania z separatorem takim jak \ d +. (O czym wiem.)
Zach Wily
72
Gdy pytanie ma tytuł awk, przyjmowanie odpowiedzi innej niż awk jest niewłaściwe. A jeśli ludzie będą potrzebować tego do skryptów awk? Ta odpowiedź powinna być tylko komentarzem.
syaz
24
@SyaZ: Normalnie się zgadzam, ale biorąc pod uwagę ilość „darmowych awk” na tej tablicy, pomyślałem, że trzeba pokazać alternatywny sposób wykonania zadania. Czy nie byłbyś wdzięczny, gdyby ktoś pokazał ci prostszy i szybszy sposób wykonania tego samego zadania? Może plakat pomyślał, że awk jest jedynym sposobem na zrobienie tego ze względu na liczbę odpowiedzi „niepoprawnych, ale z pewnością możliwych do ulepszenia” na inne pytania?
Marcin
12
Po to jest ten komentarz. Zaakceptuj najlepszą odpowiedź awk i podaj lepsze sugestie nie-awk w komentarzach. Jeśli ludzie zaczną publikować odpowiedzi, które nie odpowiadają dokładnie na pytania, będzie to denerwujące podczas wyszukiwania (w moim przypadku).
syaz
12
Nie tylko separator musi być taki sam we wszystkich kolumnach, ale między kolumnami musi znajdować się DOKŁADNIE JEDEN separator. Więc jeśli masz do czynienia z programami, które dopasowują swoje wyjście do ograniczników, lepiej jest użyć awk.
sknaumov
112
awk '{for(i=3;i<=NF;++i)print $i}' 
Jonathan Feinberg
źródło
3
awk '{for (i = 3; i <= NF; ++ i) print $ i}' jest bardziej zwarty. :)
user172818
1
Dzięki, lh3. Właśnie kopiowałem i wklejałem do podręcznika gawk. :)
Jonathan Feinberg
23
to kończy się niepowodzeniem z wieloma wierszami, każda kolumna jest traktowana jako nowa linia podczas drukowania iwth print
meso_2600
13
Aby rozwiązać problem z podzielonym wyjściem, proponuję następujące rozwiązanie: awk '{for(i=3;i<=NF;++i)printf $i""FS ; print ""}'( printfnie wydrukuje znaku nowej linii, podczas gdy print ""doda znak nowej linii po wydrukowaniu innych pól)
lauhub
1
Czyli echo $(seq 1 10) | awk '{for (i=3; i<=NF; i++) printf $i FS}', co daje: 3 4 5 6 7 8 9 10.
x-yuri
106
awk '{ print substr($0, index($0,$3)) }'

rozwiązanie znalezione tutaj:
http://www.linuxquestions.org/questions/linux-newbie-8/awk-print-field-to-end-and-character-count-179078/

daisaa
źródło
23
Trochę się spóźniłem, ale to nie zadziała dla rekordów, w których pierwsze lub drugie pole jest równe trzeciemu (np. 3 2 3 4 5)
aleph_null
drukowanie zakresu wewnętrznego jest również możliwe: `` # od 3 $ (w zestawie) do 6 $ (bez); echo "1,2,3,4,5,6,7,8,9" | awk 'BEGIN {FS = ","; OFS = ","} {print substr ($ 0, index ($ 0, $ 3), length ($ 0) -index ($ 0, $ 6) -1)}'; # daje 3,4,5 '' '
splaisan
34

Odpowiedź Jonathana Feinberga drukuje każde pole w oddzielnym wierszu. Możesz użyć printfdo odbudowania rekordu do wyjścia w tym samym wierszu, ale możesz też po prostu przesunąć pola o skok w lewo.

awk '{for (i=1; i<=NF-2; i++) $i = $(i+2); NF-=2; print}' logfile
Wstrzymano do odwołania.
źródło
1
Należy pamiętać, że działa to tylko dla Gnu awk, dekrementacja NFnie jest dozwolona przez POSIX.
kvantour
1
@kvantour: Działa w gawk, mawk, MacOS awk (nawk?). Wydaje się, że POSIX milczy na temat tego, czy NFmożna go zmniejszyć.
Wstrzymano do odwołania.
To jeden z tych śmiesznych mrocznych zakamarków awk .
kvantour
19
awk '{$1=$2=$3=""}1' file

Uwaga: ta metoda pozostawi "puste miejsca" w polach 1, 2, 3, ale nie stanowi problemu, jeśli chcesz tylko spojrzeć na wynik.

ghostdog74
źródło
Śledź to polecenie za pomocą `| sed s / ^ \ * // | kolumna -t`, aby usunąć spacje wiodące i wyrównać pozostałe kolumny
MSpreij
Co to ostatnie 1oznacza? które słowo kluczowe powinienem wyszukiwać awk?
Itachi,
@Itachi patrz przykład 1 z catonmat.net/blog/awk-one-liners-explained-part-one
kvantour
1
@Nathan, rozwiązujesz ten problem jako{$1=$2=$3="";$0=$0;$1=$1}1
kvantour
11

Jeśli chcesz wydrukować kolumny po trzeciej, na przykład w tym samym wierszu, możesz użyć:

awk '{for(i=3; i<=NF; ++i) printf "%s ", $i; print ""}'

Na przykład:

Mar 09:39 20180301_123131.jpg
Mar 13:28 20180301_124304.jpg
Mar 13:35 20180301_124358.jpg
Feb 09:45 Cisco_WebEx_Add-On.dmg
Feb 12:49 Docker.dmg
Feb 09:04 Grammarly.dmg
Feb 09:20 Payslip 10459 %2828-02-2018%29.pdf

Wydrukuje:

20180301_123131.jpg
20180301_124304.jpg
20180301_124358.jpg
Cisco_WebEx_Add-On.dmg
Docker.dmg
Grammarly.dmg
Payslip 10459 %2828-02-2018%29.pdf

Jak widać, odcinek wypłaty, nawet ze spacją, jest wyświetlany we właściwej linii.

Brat
źródło
Szybki i elegancki. Dzięki;)
9nz9
To jest doskonałe, z wyjątkiem tego, że mam problem z wykluczeniem $ NF. Kiedy ustawiam warunek (<= NF), otrzymuję ostatnie pole, ale pierwszy znak pierwszego pola jest ucinany. Czy nie rozumiem czegoś pod względem funkcjonalności?
Ken Ingram
Wygląda na to, że moim problemem jest to, że ^ M utknęło na końcu ostatniej kolumny. Nie widzę, jak to usunąć.
Ken Ingram
8

A co z następującym wierszem:

awk '{1 $ = 2 $ = 3 $ = ""; Wydrukuj plik

Na podstawie sugestii @ ghostdog74. Mój powinien zachowywać się lepiej, gdy filtrujesz linie, tj .:

awk '/ ^ exim4-config / {$ 1 = ""; Wydrukuj plik
Wawrzek
źródło
Krótkie i proste. Można również sed 's/\s\+//g'
potokować
8
awk -v m="\x0a" -v N="3" '{$N=m$N ;print substr($0, index($0,m)+1)}'

To odcina to, co znajduje się przed danym polem nr., N i wypisuje całą resztę wiersza, łącznie z polem nr N i zachowując oryginalne odstępy (nie zmienia formatowania). Nie ma znaczenia, czy ciąg pola pojawia się również gdzie indziej w wierszu, co jest problemem z odpowiedzią daisaa.

Zdefiniuj funkcję:

fromField () { 
awk -v m="\x0a" -v N="$1" '{$N=m$N; print substr($0,index($0,m)+1)}'
}

I użyj tego w ten sposób:

$ echo "  bat   bi       iru   lau bost   " | fromField 3
iru   lau bost   
$ echo "  bat   bi       iru   lau bost   " | fromField 2
bi       iru   lau bost 

Dane wyjściowe zachowują wszystko, w tym spacje końcowe

Działa dobrze w przypadku plików, w których „/ n” jest separatorem rekordów, więc nie ma znaku nowego wiersza w wierszach. Jeśli chcesz go używać z innymi separatorami rekordów, użyj:

awk -v m="\x01" -v N="3" '{$N=m$N ;print substr($0, index($0,m)+1)}'

na przykład. Działa dobrze z prawie wszystkimi plikami, o ile nie używają szesnastkowego znaku nr. 1 wewnątrz linii.

Robert Vila
źródło
4

Następujące polecenie awk drukuje N ostatnich pól każdego wiersza, a na końcu wiersza drukuje znak nowego wiersza:

awk '{for( i=6; i<=NF; i++ ){printf( "%s ", $i )}; printf( "\n"); }'

Znajdź poniżej przykład, który wymienia zawartość katalogu / usr / bin, a następnie przechowuje ostatnie 3 wiersze, a następnie wypisuje ostatnie 4 kolumny każdego wiersza przy użyciu awk:

$ ls -ltr /usr/bin/ | tail -3
-rwxr-xr-x 1 root root       14736 Jan 14  2014 bcomps
-rwxr-xr-x 1 root root       10480 Jan 14  2014 acyclic
-rwxr-xr-x 1 root root    35868448 May 22  2014 skype

$ ls -ltr /usr/bin/ | tail -3 | awk '{for( i=6; i<=NF; i++ ){printf( "%s ", $i )}; printf( "\n"); }'
Jan 14 2014 bcomps 
Jan 14 2014 acyclic 
May 22 2014 skype
boj
źródło
4
awk '{a=match($0, $3); print substr($0,a)}'

Najpierw znajdź pozycję początku trzeciej kolumny. Za pomocą substr wypisujesz całą linię ($ 0) zaczynając od pozycji (w tym przypadku a) do końca linii.

Mitchjol
źródło
3

Cóż, możesz łatwo osiągnąć ten sam efekt, używając wyrażenia regularnego. Zakładając, że separator jest spacją, wyglądałoby to tak:

awk '{ sub(/[^ ]+ +[^ ]+ +/, ""); print }'
Eddie Sullivan
źródło
1
Unikałbym wyrażenia regularnego. Prawdopodobnie wolniej i łatwiej przypadkowo zepsuć.
Cascabel
1
Skraca to w ten sposób: awk '{ sub(/([^ ]+ +){2}/, ""); print }'co dwa razy usuwa wzór.
erik
3
awk '{print ""}{for(i=3;i<=NF;++i)printf $i" "}'
luigi9876
źródło
2

Rozwiązanie Perl:

perl -lane 'splice @F,0,2; print join " ",@F' file

Używane są następujące opcje wiersza polecenia:

  • -n pętla wokół każdego wiersza pliku wejściowego, nie drukuj automatycznie każdego wiersza

  • -l usuwa nowe wiersze przed przetworzeniem i dodaje je później

  • -atryb autosplit - dzielenie linii wejściowych na tablicę @F. Domyślnie dzielenie na białe znaki

  • -e wykonać kod perla

splice @F,0,2 czysto usuwa kolumny 0 i 1 z tablicy @F

join " ",@F łączy elementy tablicy @F, używając spacji między każdym elementem

Jeśli plik wejściowy jest rozdzielany przecinkami, a nie spacjami, użyj -F, -lane


Rozwiązanie w Pythonie:

python -c "import sys;[sys.stdout.write(' '.join(line.split()[2:]) + '\n') for line in sys.stdin]" < file

Chris Koknat
źródło
1

Trochę późno tutaj, ale żadne z powyższych nie wydawało się działać. Spróbuj tego, używając printf, wstawia spacje między nimi. Zdecydowałem się nie mieć znaku nowej linii na końcu.

awk '{for(i=3;i<=NF;++i) printf("%s ",  $i) }'
Ross
źródło
1
awk '{for (i=4; i<=NF; i++)printf("%c", $i); printf("\n");}'

drukuje rekordy począwszy od czwartego pola do ostatniego pola w tej samej kolejności, w jakiej znajdowały się w oryginalnym pliku

Massimo
źródło
przepraszam, to nie była całkiem poprawna odpowiedź. jest zbyt szczegółowy, ale nie wiem, jak go usunąć
Massimo
1

W Bash możesz użyć następującej składni z parametrami pozycyjnymi:

while read -a cols; do echo ${cols[@]:2}; done < file.txt

Dowiedz się więcej: Obsługa parametrów pozycyjnych na stronie Bash Hackers Wiki

kenorb
źródło
0

Jeśli chodzi tylko o zignorowanie pierwszych dwóch pól i jeśli nie chcesz spacji podczas maskowania tych pól (tak jak robią to niektóre z powyższych odpowiedzi):

awk '{gsub($1" "$2" ",""); print;}' file
champost
źródło
0
awk '{$1=$2=""}1' FILENAME | sed 's/\s\+//g'

Pierwsze dwie kolumny są wyczyszczone, sedusuwa spacje wiodące.

sjas
źródło
-2

W kolumnach AWK nazywane są polami, stąd kluczem jest NF

wszystkie rzędy:

awk -F '<column separator>' '{print $(NF-2)}' <filename>

tylko pierwszy rząd:

awk -F '<column separator>' 'NR<=1{print $(NF-2)}' <filename>
angelo.mastro
źródło