Comment imprimer les deux dernières colonnes en utilisant awk

106

Tout ce que je veux, ce sont les deux dernières colonnes imprimées.

vehomzzz
la source
6
Je ne sais pas trop pourquoi cela a 87 votes positifs, il peut certainement être amélioré avec un exemple au moins.
Arj
Probablement parce que la question est extrêmement simple par nature et facile à comprendre sans exemple, ce qui est rare, mais dans ce cas, cela semble fonctionner. Le problème ici n'est pas le manque d'informations je pense, mais plutôt le fait que cela montre un manque de recherche indépendante.
DryLabRebel
Cette question est également un double de cette question.
DryLabRebel
Est-ce que cela répond à votre question? Imprimer l'avant-dernière colonne / champ dans awk
DryLabRebel

Réponses:

194

Vous pouvez utiliser la variable NFqui correspond au nombre total de champs dans l'enregistrement d'entrée:

awk '{print $(NF-1),"\t",$NF}' file

cela suppose que vous ayez au moins 2 champs.

codaddict
la source
1
Vous avez besoin d'une virgule - puisque nous sommes pointilleux aujourd'hui: l'espace concatène les champs, la virgule sépare les champs dans une instruction d'impression. Cela fusionnera les deux champs
jim mcnamara
18
Vous imprimez maintenant "champ-OFS-tab-OFS-champ". Cela devrait être awk '{print $(NF-1) "\t" $NF}' fileou awk '{print $(NF-1), $NF}' fileou awk 'BEGIN{OFS="\t"} {print $(NF-1), $NF}' file.
Suspendu jusqu'à nouvel ordre.
Juste pour ajouter au commentaire précédent, le problème avec l'utilisation '{print $x,"\t",$y}'est que awk interprète chaque variable séparée par des virgules comme son propre champ, donc le résultat sera en fait field1<space><tab><space>field2, (car il utilisera un délimiteur d'espace blanc par défaut) par opposition à field1<tab>field2ce qui est probablement ce vous attendez. l'utilisation du séparateur de champ de sortie (OFS) est presque toujours ce que vous voulez.
DryLabRebel
13
awk '{print $NF-1, $NF}'  inputfile

Remarque: cela ne fonctionne que s'il existe au moins deux colonnes. Sur les enregistrements avec une colonne, vous obtiendrez un faux"-1 column1"

Jim Mcnamara
la source
3
Essayez et voyez. Cela fonctionne avec Solaris 9 awk & nawk. L'alternative est $ (NF-1)
jim mcnamara
1
@coaddict - Je suppose que vous n'avez pas travaillé avec différentes implémentations awk. De vieux comportements awks ont été (peut-être à tort) mis en avant. Je n'ai pas de gawk à tester - ce à quoi vous faites probablement référence. Je ne sais donc pas avec certitude pourquoi votre commentaire a été ignoré. Linux awk hors de la boîte est généralement gawk. Je vais tester et poster en retour. En attendant, essayez Soalris ou HPUX ou DGX ou autre pour voir ce que je veux dire par vieux awk.
jim mcnamara
6
Vous avez probablement été amené à penser que cela fonctionnait parce que vous avez essayé echo 1 2 3 | awk .... $NF-1est ($NF) - 1dans chaque awkmise en œuvre.
Stephane Chazelas
Le code source "One True Awk" a plus de 40 conflits dans la yaccgrammaire, ce qui est ironique étant donné ce que le A représente dans awk. Différentes versions de awk analysant les choses différemment? Grosse surprise!
Kaz
1
@THESorcerer, essayez avec echo '5 4 3 2 1' | awk '{print $NF-1,$NF; print $(NF-1), $NF}'- ou toute autre entrée où le 2ème dernier champ n'est pas un de moins que le dernier champ.
glenn jackman
6

@jim mcnamara: essayez d'utiliser des parenthèses pour autour NF, c'est-à $(NF-1)- dire et $(NF)au lieu de $NF-1et $NF(fonctionne sur Mac OS X 10.6.8 pour FreeBSD awket gawk).

echo '
1 2
2 3
one
one two three
' | gawk '{if (NF >= 2) print $(NF-1), $(NF);}'

# output:
# 1 2
# 2 3
# two three
guzo
la source
Nous avions déjà envisagé () plus tôt. Je pensais que nous discutions de l'origine du comportement original de l'ancien awk.
jim mcnamara
+1 pour une réponse avec explicite $(NF-1)- qui au moins est plus portable que $NF-1; c'est nettement moins ambigu. $(NF)est exagéré, cependant - $NFfera juste . Se protéger contre les lignes de moins de 2 colonnes vaut également la peine, car avec des lignes à une colonne, vous obtiendrez la première valeur de la première colonne deux fois , et avec des lignes de colonne zéro - c'est-à-dire vides - la commande awk échouerait complètement en raison d'une tentative pour accéder à un champ d'index -1.
mklement0
1

l'utilisation de gawk présente le problème:

 gawk '{ print $NF-1, $NF}' filename
1 2
2 3
-1 one
-1 three
# cat filename
1 2
2 3
one
one two three

Je viens de mettre gawk sur Solaris 10 M4000: Donc, gawk est le cuplrit sur le problème $ NF-1 vs $ (NF-1). Question suivante que dit POSIX? par:

http://www.opengroup.org/onlinepubs/009695399/utilities/awk.html

Il n'y a pas de direction dans un sens ou dans l'autre. Pas bon. gawk implique une soustraction, d'autres awks impliquent un numéro de champ ou une soustraction. hmm.

Jim Mcnamara
la source
1
Les 2 premières lignes de votre exemple de fichier d'entrée ne sont pas utiles car elles produisent la même sortie avec l'un ou l' autre comportement. Pouvez-vous s'il vous plaît reconfirmer que Solaris awk ne se comporte en effet PAS comme gawk dans ce cas?
mklement0
Quant à votre lien vers la spécification awk: L'argument anecdotique pour l'utilisation $(NF-1)est que les deux exemples de calcul de l'index de champ dans la spécification utilisent tous deux cette forme: $(NF-1)et $(NF+2). Ensuite, il y a la section "Expressions dans awk", qui indique $exprcomme ayant une priorité [beaucoup] plus élevée que expr - expr. Puisque NFest une expression elle-même, $NF-1devrait s'évaluer ($NF)-1. Même SI, après tout, il existe en effet des implémentations awk qui évaluent $NF-1comme $(NF-1), la leçon apprise ici est que l'utilisation $(NF-1)est le choix sûr et portable.
mklement0
0

essayez avec ça

$ cat /tmp/topfs.txt
/dev/sda2      xfs        32G   10G   22G  32% /

awk print last column
$ cat /tmp/topfs.txt | awk '{print $NF}'

awk print before last column
$ cat /tmp/topfs.txt | awk '{print $(NF-1)}'
32%

awk - print last two columns
$ cat /tmp/topfs.txt | awk '{print $(NF-1), $NF}'
32% /
namasivayam.cse
la source
0

Veuillez essayer ceci pour prendre en compte tous les scénarios possibles:

awk '{print $(NF-1)"\t"$NF}'  file

ou

awk 'BEGIN{OFS="\t"}' file

ou

awk '{print $(NF-1), $NF} {print $(NF-1), $NF}' file
Marios Karamanis
la source