Come stampare tutte le colonne dopo un numero particolare usando awk?


90

Su shell, eseguo il pipe per awk quando ho bisogno di una colonna particolare.

Stampa la colonna 9, ad esempio:

... | awk '{print $9}'

Come posso dire a awk di stampare tutte le colonne inclusa e dopo la colonna 9 , non solo la colonna 9?


Risposte:


83
awk '{ s = ""; for (i = 9; i <= NF; i++) s = s $i " "; print s }'

3
un paio di piccoli perfezionamenti:awk -v N=9 '{sep=""; for (i=N; i<=NF; i++) {printf("%s%s",sep,$i); sep=OFS}; printf("\n")}'
glenn jackman

Grazie @glenn, questo è davvero un po 'più generale. Comunque, sarei decisamente d'accordo che sarebbe meglio usare cuto perlper questo. Usalo solo se insisti davvero per averlo awk.
Amadan

1
@SiegeX: non aggiunge byte NUL, lascia il FS in posizione tra ogni campo vuoto.
Dennis Williamson

1
Si prega di vedere la risposta di @ Ascherer per l'eleganza.

3
@veryhungrymike: L'eleganza è bella, ma preferisco essere corretto. : p
Amadan

68

Quando vuoi fare una serie di campi, awknon hai davvero un modo semplice per farlo. Consiglierei cutinvece:

cut -d' ' -f 9- ./infile

modificare

Aggiunto delimitatore di campo spazio perché l'impostazione predefinita è una scheda. Grazie a Glenn per averlo fatto notare


15
Una cosa su cut è che utilizza un delimitatore specifico (tab per impostazione predefinita), dove awk usa "spazi bianchi". Con il taglio, 2 tabulazioni consecutive delimitano un campo vuoto.
glenn jackman

1
Come ha sottolineato @glennjackman, il delimitatore di awk è "spazi bianchi" (anche qualsiasi importo). Quindi l'impostazione del delimitatore di taglio su uno spazio singolo non corrisponderebbe anche al comportamento. sfortunatamente il ciclo è il migliore che si possa fare, quindi sembra.
poncha

Questo non funziona correttamente. Prova il comando find . | xargs ls -l | cut -d' ' -f 9-. Per qualche ragione vengono contati anche i doppi spazi. Esempio: lrwxrwxrwx 1 me me 21 Dec 12 00:00 ./file_a lrwxrwxrwx 1 me me 64 Dec 6 00:06 ./file_bsi tradurrà in./file_a 00:06 ./file_b
Marco Pashkov

@MarcoPashkov per favore approfondisci Questo non funziona correttamente , soprattutto considerando che usi esattamente lo stesso codice nella tua pipeline. A proposito, non dovresti mai provare ad analizzare l'output di ls
SiegeX

il taglio non fa il lavoro qui. Ad esempio, se il tuo input è "foo bar" (spazio singolo) per una riga e "foo ___ bar" (cioè più spazi, ma SO è troppo intelligente per mostrarlo) per un altro, cut li elaborerà in modo diverso.
UKMonkey

54
awk '{print substr($0, index($0,$9))}'

Modifica : nota, questo non funziona se un campo prima del nono contiene lo stesso valore del nono.


10
@veryhungrymike: ... e non funziona se un campo prima del nono contiene lo stesso valore del nono.
Amadan

6
Probabilmente a causa della classica frase "si spera che il tuo file non abbia questo problema". È un no-no totale nell'ingegneria s / w affermare: "non perderemo tempo incluso il controllo degli errori per l'inserimento di valori negativi, ad esempio, perché" speriamo che l'utente sia abbastanza intelligente da non provarli mandando in crash il nostro strumento '". HAHAHA! Mi piace sempre sentire questo! (Mi piace un buon senso dell'umorismo) Beh, come idioti fanno esistere, è il dovere dello sviluppatore a fare la sua roba a prova di idiota ! Invece di "sperare nel bene dell'uomo". Questo è piuttosto un atteggiamento previsto dai filosofi, non dagli ingegneri del s / w ... LOL
syntaxerror

3
Non stavo dicendo di non controllare gli errori, ma se sai che non ti imbatterai nel problema, allora questa soluzione va bene, come ho affermato. Ma grazie per l'inutile downvote @syntaxerror. Questa soluzione funzionerà per alcuni, come mostreranno i 19 voti positivi (attualmente), ma in caso contrario, non usarla per la tua soluzione. Ci sono molti modi per risolvere il problema dell'OP.
Ascherer

1
Se stai usando awk sulla riga di comando nel tuo lavoro quotidiano, questa è sicuramente la soluzione che desideri. Non è ovvio? Il controllo degli errori, ecc., Non ha molta importanza in questo caso poiché lo stai digitando e puoi catturare questo genere di cose prima di premere Invio (personalmente, non penso che awk dovrebbe essere usato per qualcos'altro comunque, ecco perché noi 'ho perl, python, tcl e circa 100+ altri linguaggi di scripting migliori, più veloci e meno fastidiosi!)' Naturalmente forse sto dando troppo credito ai miei colleghi sviluppatori di software e hanno davvero bisogno di controllare gli errori anche sulle cose che scrivono al volo (??)
osirisgothra

1
Non che ne avesse bisogno, perché è proprio sotto la risposta, ma l'ho aggiunto @atti
Ascherer

11
sed -re 's,\s+, ,g' | cut -d ' ' -f 9-

Invece di occuparsi di spazi bianchi a larghezza variabile, sostituire tutti gli spazi bianchi come spazio singolo. Quindi usa semplice cutcon i campi di interesse.

Non usa awk, quindi non è pertinente ma sembrava appropriato date le altre risposte / commenti.


1
Per favore, rendi la tua risposta più esauriente, altrimenti pubblicala come commento alla domanda.
Alper Turan

Questo è l'ideale per l' ps faux | uso. Non aver mai paura di ammettere che lo strumento XYZ non è il più appropriato.
kevinf

10

Generalmente perl sostituisce awk / sed / grep et. al., ed è molto più portabile (oltre ad essere solo un temperino migliore).

perl -lane 'print "@F[8..$#F]"'

Timtowtdi si applica ovviamente.


È necessario aggiungere un'opzione della riga di comando -lo aggiungere \nall'istruzione print.
glenn jackman

@glenn jackman: forse. Non richiesto se fa parte di un altro messaggio, o se viene assegnato a una variabile, ecc. Per quanto riguarda "meglio", perl ha sicuramente un aspetto migliore nel piccolo. Può sembrare molto disordinato in generale, ammettiamolo.
bobbogo

Non fraintendermi, mi piace Perl. Adoro awk per quello che è però.
glenn jackman

Il mio dispositivo incorporato non viene fornito con Perl, ma ha awk.
Sepero

Downvoting perché la domanda chiedeva come farlo in awk, non perl, ruby, java, python, bash.
Tom Harrison,

3
awk -v m="\x01" -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 nrN 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 Ascherer.

Definisci una funzione:

fromField () { 
awk -v m="\x01" -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 mantiene tutto, inclusi gli spazi finali Per N = 0 restituisce l'intera riga, così com'è, e per n> NF la stringa vuota


Questa è una buona idea. Non funziona su un Mac corrente che utilizza il tipico gawk, perché $ 0 crolla. La soluzione consiste nell'impostare una variabile su $ 0 come primo passaggio, ad esempio: '{s = $ 0; ... print substr (s, index (s, m) +1}
joelparkerhenderson

1

Ecco un esempio di ls -loutput:

-rwxr-----@ 1 ricky.john  1493847943   5610048 Apr 16 14:09 00-Welcome.mp4
-rwxr-----@ 1 ricky.john  1493847943  27862521 Apr 16 14:09 01-Hello World.mp4
-rwxr-----@ 1 ricky.john  1493847943  21262056 Apr 16 14:09 02-Typical Go Directory Structure.mp4
-rwxr-----@ 1 ricky.john  1493847943  10627144 Apr 16 14:09 03-Where to Get Help.mp4

La mia soluzione per stampare qualsiasi post $9èawk '{print substr($0, 61, 50)}'



0

Per visualizzare i primi 3 campi e stampare i campi rimanenti puoi utilizzare:

awk '{s = ""; for (i=4; i<= NF; i++) s= s $i : "; print $1 $2 $3 s}' filename

dove $ 1 $ 2 $ 3 sono i primi 3 campi.


0
function print_fields(field_num1, field_num2){
    input_line = $0

    j = 1;
    for (i=field_num1; i <= field_num2; i++){
        $(j++) = $(i);

    }
    NF = field_num2 - field_num1 + 1;
    print $0

    $0 = input_line
}

0

Usare cut invece di awk e superare i problemi con la determinazione della colonna da cui iniziare usando il comando -c character cut.

Qui sto dicendo, dammi tutto tranne i primi 49 caratteri dell'output.

 ls -l /some/path/*/* | cut -c 50-

Alla /*/*/fine del comando ls sta dicendo mostrami anche cosa c'è nelle sottodirectory.

Puoi anche estrarre alcuni intervalli di caratteri ala (dalla pagina man di cut). Ad esempio, mostra i nomi e gli orari di accesso degli utenti attualmente connessi:

       who | cut -c 1-16,26-38
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.