web-dev-qa-db-fra.com

Comment imprimer uniquement la dernière colonne?

echo -e 'one two three\nfour five six\nseven eight nine'
one two three
four five six
seven eight nine

comment puis-je faire un "MAGIC" pour obtenir cette sortie?:

three
six
nine

MISE À JOUR: Je n'en ai pas besoin de cette manière spécifique, j'ai besoin d'une solution générale pour que peu importe le nombre de colonnes dans une ligne, par exemple: awk affiche toujours la dernière colonne.

27
LanceBaynes

Cela ne peut même se faire qu'avec 'bash', sans pour autant 'sed', 'awk' ou 'Perl':

echo -e 'one two three\nfour five six\nseven eight nine' |
  while IFS=" " read -r -a line; do
    nb=${#line[@]}
    echo ${line[$((nb - 1))]}
  done
6
jfg956

Essayer:

echo -e 'one two three\nfour five six\nseven eight nine' | awk '{print $NF}'
57
Sean C.

C'est plus facile que vous ne le pensez.

$ echo one two three | awk '{print $NF}'
three
15
bahamat

Essayez grep (plus court/plus simple, mais 3 fois plus lent que awk en raison de l'utilisation de l'expression régulière):

grep -o '\S\+$' <(echo -e '... seven eight nine')

Ou ex (encore plus lent, mais il imprime tout le tampon après la fin, plus utile lorsqu'il doit être trié ou modifié sur place):

ex -s +'%s/^.*\s//g' -c'%p|q!' <(echo -e '... seven eight nine')
ex +'%norm $Bd0' -sc'%p|q!' infile

Pour changer sur place, remplacez -sc'%p|q!' avec -scwq.

Ou bash:

while read line; do arr=($line); echo ${arr[-1]}; done < someinput

Performance

Compte tenu du fichier 1 Go généré via:

$ hexdump -C /dev/urandom | rev | head -c1G | pv > datafile

J'ai effectué les statistiques de temps d'analyse (exécuté ~ 3x et pris le plus bas, testé sur MBP OS X):

  • en utilisant awk:

    $ time awk '{print $NF}' datafile > /dev/null
    real    0m12.124s
    user    0m10.704s
    sys 0m0.709s
    
  • en utilisant grep:

    $ time grep -o '\S\+$' datafile > /dev/null
    real    0m36.731s
    user    0m36.244s
    sys 0m0.401s
    
    $ time grep -o '\S*$' datafile > /dev/null
    real    0m40.865s
    user    0m39.756s
    sys 0m0.415s
    
  • en utilisant Perl:

    $ time Perl -lane 'print $F[-1]' datafile > /dev/null
    real    0m48.292s
    user    0m47.601s
    sys 0m0.396s
    
  • en utilisant rev + cut:

    $ time (rev|cut -d' ' -f1|rev) < datafile > /dev/null
    $ time rev datafile | cut -d' ' -f1 | rev > /dev/null
    real    1m10.342s
    user    1m19.940s
    sys 0m1.263s
    
  • en utilisant ex:

    $ time ex +'%norm $Bd0_' -sc'%p|q!' datafile > /dev/null
    real    3m47.332s
    user    3m42.037s
    sys 0m2.617s
    $ time ex +'%norm $Bd0' -sc'%p|q!' datafile > /dev/null
    real    4m1.527s
    user    3m44.219s
    sys 0m6.164s
    $ time ex +'%s/^.*\s//g' -sc'%p|q!' datafile > /dev/null
    real    4m16.717s
    user    4m5.334s
    sys 0m5.076s
    
  • en utilisant bash:

    $ time while read line; do arr=($line); echo ${arr[-1]}; done < datafile > /dev/null
    real    9m42.807s
    user    8m12.553s
    sys 1m1.955s
    
12
kenorb
... | Perl -lane 'print $F[-1]'
6
glenn jackman

Cela peut également être fait en utilisant 'sed':

echo -e 'one two three\nfour five six\nseven eight nine' | sed -e 's/^.* \([^ ]*\)$/\1/'

Mise à jour:

ou plus simplement:

echo -e 'one two three\nfour five six\nseven eight nine' | sed -e 's/^.* //'
5
jfg956

Ou en utilisant cut :

echo -e 'one two three\nfour five six\nseven eight nine' | cut -f 3 -d' '

bien que cela ne réponde pas à l'exigence de "solution générale". En utilisant rev deux fois, nous pouvons également résoudre ce problème:

echo -e 'one two three\nfour five six\nseven eight nine' | rev | cut -f 1 -d' ' | rev
5
Tim

En utilisant awk, vous pouvez d'abord vérifier s'il y a au moins une colonne.

echo | awk '{if (NF >= 1) print $NF}'

echo 1 2 3 | awk '{if (NF >= 1) print $NF}'
2
gezu

En Perl, cela peut être fait comme suit:

#!/usr/bin/Perl

#create a line of arbitrary data
$line = "1 2 3 4 5";

# splt the line into an array (we call the array 'array', for lolz)
@array = split(' ', $line);

# print the last element in the array, followed by a newline character;
print "$array[-1]\n";

production:

$ Perl last.pl
5
$

Vous pouvez également parcourir un fichier en boucle, voici un exemple de script que j'ai écrit pour analyser un fichier appelé budget.dat

exemples de données dans budget.dat:

Rent              500
Food              250
Car               300
Tax               100
Car Tax           120
Mag Subscription  15

(vous pouvez voir que je devais capturer uniquement la "dernière" colonne, pas seulement la colonne 2)

Le scénario:

#!/usr/bin/Perl
$budgetfile = "budget.dat";
open($bf, $budgetfile)
        or die "Could not open filename: $filename $!";


print "-" x 50, "\n";
while ( $row = <$bf> ) {
        chomp $row;
        @r = split (' ', $row);
        print "$row ";
        $subtotal += $r[-1];
        print "\t$subtotal\n";
}
print "-" x 50, "\n";
print "\t\t\t Total:\t$subtotal\n\n";
1
urbansumo