Come stampare dalla terza all'ultima colonna?


Risposte:


108

... o una soluzione più semplice: cut -f 3- INPUTFILE aggiungi semplicemente il delimitatore corretto (-d) e ottieni lo stesso effetto.


9
Nota che questo funziona solo se il delimitatore è esattamente lo stesso tra tutte le colonne ... Ad esempio, non puoi usare cut con un delimitatore come \ d +. (Che io sappia.)
Zach Wily

72
Quando la domanda è intitolata awk, non è appropriato accettare una risposta diversa da awk. E se le persone ne avessero bisogno per gli script awk? Questa risposta avrebbe dovuto essere solo un commento.
syaz

24
@SyaZ: Normalmente sarei d'accordo, ma con la quantità di "awk gratuito" presente su questo forum, ho pensato che fosse necessario per mostrare un modo alternativo di svolgere il compito. Non saresti grato se qualcuno ti mostrasse un modo più semplice e veloce per svolgere lo stesso compito? Forse il poster pensava che awk fosse l'unico modo per farlo a causa del numero di risposte "non errate, ma sicuramente migliorabili" ad altre domande?
Marcin

12
Ecco a cosa serve il commento. Accetta la migliore risposta awk e fornisci suggerimenti migliori non awk sui commenti. Se le persone iniziano a pubblicare risposte che non rispondono esattamente alle domande, sarà fastidioso durante la ricerca (nel mio caso).
syaz

12
Non solo il delimitatore deve essere lo stesso tra tutte le colonne, ma deve esserci ESATTAMENTE UN carattere delimitatore tra le colonne. Quindi, se hai a che fare con programmi che allineano il loro output con i delimitatori, è meglio usare awk.
sknaumov

112
awk '{for(i=3;i<=NF;++i)print $i}' 

3
awk '{for (i = 3; i <= NF; ++ i) print $ i}' essere più compatto. :)
user172818

1
Grazie, lh3. Stavo solo copiando e incollando per il manuale gawk. :)
Jonathan Feinberg

23
questo fallisce con più righe, ogni colonna viene considerata come una nuova riga quando viene stampata con la stampa
meso_2600

13
Per risolvere il problema dell'output diviso, propongo questa soluzione: awk '{for(i=3;i<=NF;++i)printf $i""FS ; print ""}'( printfnon stamperà il carattere di nuova riga mentre print ""aggiungerà una nuova riga dopo che gli altri campi sono stati stampati)
lauhub

1
Oppure: echo $(seq 1 10) | awk '{for (i=3; i<=NF; i++) printf $i FS}'che dà: 3 4 5 6 7 8 9 10.
x-yuri

106

23
Sono un po 'in ritardo per questo, ma non funzionerà per i record in cui il primo o il secondo campo è uguale al terzo (ad esempio, 3 2 3 4 5)
aleph_null

è anche possibile stampare un intervallo interno: `` `# da $ 3 (incluso) a $ 6 (escluso); 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)}'; # dà 3,4,5 ''
splaisan

34

La risposta di Jonathan Feinberg stampa ogni campo su una riga separata. Potresti usare printfper ricostruire il record per l'output sulla stessa riga, ma puoi anche spostare i campi di un salto a sinistra.

awk '{for (i=1; i<=NF-2; i++) $i = $(i+2); NF-=2; print}' logfile

1
Tieni presente che funziona solo per Gnu awk, il decremento NFnon è consentito da POSIX.
kvantour

1
@kvantour: Funziona in gawk, mawk, MacOS awk (nawk?). POSIX sembra tacere sull'opportunità di NFdecrementare.
In pausa fino a nuovo avviso.

È uno di questi divertenti angoli oscuri di awk .
kvantour

19
awk '{$1=$2=$3=""}1' file

NB: questo metodo lascerà "spazi vuoti" nei campi 1,2,3 ma non è un problema se vuoi solo guardare l'output.


Segui quel comando con `| sed s / ^ \ * // | colonna -t` per rimuovere gli spazi iniziali e allineare le colonne rimanenti
MSpreij

Cosa significa l'ultimo 1? con quale parola chiave devo cercare awk?
Itachi


1
@ Nathan risolvi questo problema come{$1=$2=$3="";$0=$0;$1=$1}1
kvantour

11

Se vuoi stampare le colonne dopo la 3 ° ad esempio nella stessa riga, puoi usare:

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

Per esempio:

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

Stamperà:

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

Come possiamo vedere, la busta paga anche con lo spazio, viene visualizzata nella riga corretta.


Veloce ed elegante. Grazie;)
9nz9

Questo è eccellente, tranne che ho un problema con l'esclusione di $ NF. Quando imposto la condizione (<= NF) ottengo l'ultimo campo ma il primo carattere del primo campo viene troncato. Sto fraintendendo qualcosa in termini di funzionalità?
Ken Ingram,

Sembra che il mio problema sia che ^ M è bloccato alla fine dell'ultima colonna. Non vedo come rimuoverlo.
Ken Ingram il

8

Che dire della seguente riga:

awk "{$ 1 = $ 2 = $ 3 =" "; stampa file

Basato sul suggerimento di @ ghostdog74. Il mio dovrebbe comportarsi meglio quando filtri le linee, ovvero:

awk '/ ^ exim4-config / {$ 1 = ""; stampa file

Breve e semplice. Potrebbe anche aggiungere e aggiungere sed 's/\s\+//g'alla fine del comando per tagliare gli spazi
iniziali

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

Questo taglia ciò che è prima del campo nr., N, e stampa tutto il resto della riga, incluso il campo nr.N e mantenendo la spaziatura originale (non si riformatta). Non importa se la stringa del campo appare anche da qualche altra parte nella riga, che è il problema con la risposta di Daisaa.

Definisci una funzione:

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

E usalo in questo modo:

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

L'output conserva tutto, inclusi gli spazi finali

Funziona bene per i file in cui '/ n' è il separatore di record, quindi non hai quel carattere di nuova riga all'interno delle righe. Se vuoi usarlo con altri separatori di record, usa:

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

per esempio. Funziona bene con quasi tutti i file purché non utilizzino il carattere esadecimale nr. 1 all'interno delle righe.


4

Il seguente comando awk stampa gli ultimi N campi di ogni riga e alla fine della riga stampa un nuovo carattere di riga:

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

Di seguito è riportato un esempio che elenca il contenuto della directory / usr / bin e quindi contiene le ultime 3 righe e quindi stampa le ultime 4 colonne di ciascuna riga utilizzando 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

4
awk '{a=match($0, $3); print substr($0,a)}'

Per prima cosa trovi la posizione dell'inizio della terza colonna. Con substr stamperai l'intera riga ($ 0) a partire dalla posizione (in questo caso a) fino alla fine della riga.


3

Bene, puoi facilmente ottenere lo stesso effetto usando un'espressione regolare. Supponendo che il separatore sia uno spazio, sarebbe simile a:

awk '{ sub(/[^ ]+ +[^ ]+ +/, ""); print }'

1
Eviterei regex. Probabilmente è più lento e più facile rovinare accidentalmente.
Cascabel

1
Lo accorcia in questo modo: il awk '{ sub(/([^ ]+ +){2}/, ""); print }'che toglie lo schema due volte.
erik


2

Soluzione Perl:

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

Vengono utilizzate queste opzioni della riga di comando:

  • -n ciclo attorno a ogni riga del file di input, non stampa automaticamente ogni riga

  • -l rimuove le nuove righe prima dell'elaborazione e le aggiunge nuovamente in seguito

  • -amodalità autosplit: suddivide le linee di input nell'array @F. Il valore predefinito è la divisione su spazi bianchi

  • -e eseguire il codice perl

splice @F,0,2 rimuove in modo pulito le colonne 0 e 1 dall'array @F

join " ",@F unisce gli elementi dell'array @F, utilizzando uno spazio tra ogni elemento

Se il file di input è delimitato da virgole, anziché delimitato da spazi, utilizza -F, -lane


Soluzione Python:

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


1

Un po 'tardi qui, ma nessuno dei precedenti sembrava funzionare. Prova questo, usando printf, inserisce spazi tra ciascuno. Ho scelto di non avere una nuova riga alla fine.

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

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

stampa i record a partire dal 4 ° campo all'ultimo campo nello stesso ordine in cui erano nel file originale


scusa, questa non era una risposta del tutto corretta. è troppo specifico, ma non so come cancellarlo
Massimo


0

Se si tratta solo di ignorare i primi due campi e se non si desidera uno spazio quando si mascherano quei campi (come fanno alcune delle risposte sopra):

awk '{gsub($1" "$2" ",""); print;}' file

0
awk '{$1=$2=""}1' FILENAME | sed 's/\s\+//g'

Le prime due colonne vengono cancellate, sedrimuove gli spazi iniziali.


-2

In AWK le colonne sono chiamate campi, quindi NF è la chiave

tutte le righe:

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

solo prima riga:

awk -F '<column separator>' 'NR<=1{print $(NF-2)}' <filename>
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.