Comment couper (sélectionner) un champ de la ligne de texte comptant à partir de la fin?

32

Je sais comment sélectionner un champ dans une ligne à l'aide de la commande de coupe. Par exemple, compte tenu des données suivantes:

a,b,c,d,e
f,g,h,i,j
k,l,m,n,o

Cette commande:

cut -d, -f2 # returns the second field of the input line

Résultats:

b
g
l

Ma question: Comment puis-je sélectionner le deuxième champ à compter de la fin? Dans l'exemple précédent, le résultat serait:

d
i
n
ssn
la source

Réponses:

52

Inverser l'entrée avant et après cutavec rev:

<infile rev | cut -d, -f2 | rev

Sortie:

d
i
n
Thor
la source
1
J'ai beaucoup de petits extraits dans mon dossier bin. rcut est précisément pour cela: #! / bin / bash rev | couper "$ @" | rev
John Allsup
2
Dommage qu'il cutne soit pas possible de prendre des index de champs négatifs (comme Python).
Keith Devens
10

Essayez de faire ceci avec :

awk -F, '{print $(NF-1)}' file.txt

Ou en utilisant :

perl -F, -lane 'print $F[-2]' file.txt

Ou en utilisant (merci manatwork):

ruby -F, -lane 'print $F[-2]' file.txt

Ou en utilisant bash(merci manatwork):

while IFS=, read -ra d; do echo "${d[-2]}"; done < file.txt

Ou en utilisant :

cat file.txt |
python -c $'import sys\nfor line in sys.stdin:\tprint(line.split(",")[-2])'
Gilles Quenot
la source
1
bashil ne faille pas le nombre de colonnes fixe pour cela: while IFS=, read -ra d; do echo "${d[-2]}"; done < file.txt.
manatwork
1
BTW, votre troisième solution fonctionne également si vous changez perlavec ruby.
Manatwork
Merci, rubyajouté, bashédité.
Gilles Quenot
1
Si le 4ème champ peut commencer par -ou (en fonction de l'environnement, du shell ou de la manière dont le shell a été compilé), peut contenir des caractères de barre oblique inverse, ce echon'est pas une option. Pourquoi avez-vous besoin de catconsommer file.txtsans rien avant de le nourrir python!?. Vous avez besoin au read -Alieu de read -adans ksh93et zsh. Les indices négatifs fonctionnent dans, zshmais seulement dans les versions récentes de ksh93et bash. Dans les anciennes versions, vous pouvez utiliser${d: -2:1}
Stéphane Chazelas
2
@ StephaneChazelas, je pense que vous voulez dire ${d[@]: -2:1}dans votre dernière phrase.
manatwork
0

Utilisation de sed:

sed -E 's/^([^,]*,)*([^,]*)(,[^,]*){1}$/\2/' infile

Sortie:

d
i
n

Explication

  • ([^,]*,)* correspond à un nombre quelconque de caractères sans virgule suivis d'une virgule, c'est-à-dire un nombre quelconque de colonnes.
  • ([^,]*) correspond à une colonne.
  • (,[^,]*){1}correspond à une colonne à la fin, si vous modifiez le quantificateur {1}pour {2}qu'il corresponde à la deuxième colonne à partir de la fin, etc.
Thor
la source