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.
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
Essayer:
echo -e 'one two three\nfour five six\nseven eight nine' | awk '{print $NF}'
C'est plus facile que vous ne le pensez.
$ echo one two three | awk '{print $NF}'
three
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
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
... | Perl -lane 'print $F[-1]'
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/^.* //'
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
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}'
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";