web-dev-qa-db-fra.com

Comment supprimer la dernière colonne d'un fichier sous Linux

Je souhaite supprimer la dernière colonne d'un fichier txt, alors que je ne connais pas le numéro de colonne. Comment pourrais-je faire ça?

Exemple:

Contribution:

1223 1234 1323 ... 2222 123
1233 1234 1233 ... 3444 125
0000 5553 3455 ... 2334 222

Et je veux que ma sortie soit:

1223 1234 1323 ... 2222
1233 1234 1233 ... 3444
0000 5553 3455 ... 2334
25
zara

Avec awk:

awk 'NF{NF-=1};1' <in >out

ou:

awk 'NF{NF--};1' <in >out

ou:

awk 'NF{--NF};1' <in >out

Bien que cela ressemble à du vaudou, cela fonctionne. Chacune de ces commandes awk comprend trois parties.

Le premier est NF, qui est une condition préalable pour la deuxième partie. NF est une variable contenant le nombre de champs dans une ligne. Dans AWK, les choses sont vraies si elles ne sont pas 0 ou une chaîne vide "". Par conséquent, la deuxième partie (où NF est décrémentée) ne se produit que si NF n'est pas 0.

La deuxième partie (soit NF-=1NF-- ou --NF) est juste en soustrayant un de la variable NF. Cela empêche l'impression du dernier champ, car lorsque vous modifiez un champ (en supprimant le dernier champ dans ce cas), awk re-construct $0, concatène tous les champs séparés par un espace par défaut. $0 ne contenait plus le dernier champ.

La dernière partie est 1. Ce n'est pas magique, c'est juste utilisé comme une expression qui signifie true. Si une expression awk a la valeur true sans aucune action associée, awk l'action par défaut est print $0.

43
cuonglm

Utilisation de grep avec PCRE:

$ grep -Po '.*(?=\s+[^\s]+$)' file.txt 
1223 1234 1323 ... 2222
1233 1234 1233 ... 3444
0000 5553 3455 ... 2334

Utilisation de GNU sed:

$ sed -r 's/(.*)\s+[^\s]+$/\1/' file.txt 
1223 1234 1323 ... 2222
1233 1234 1233 ... 3444
0000 5553 3455 ... 2334
16
heemayl

Utilisation de Perl:

Perl -lane '$,=" ";pop(@F);print(@F)' in

Utilisation de rev + cut:

rev in | cut -d ' ' -f 2- | rev
14
kos

Utilisation de GNU sed:

sed -r 's/\s+\S+$//' input.txt

Plus généralement, celui-ci fonctionne avec le BSD sed dans OSX, ainsi que GNU sed:

sed 's/[[:space:]]\{1,\}[^[:space:]]\{1,\}$//' input.txt
5
Digital Trauma

Vous pouvez utiliser l'un ou l'autre de ces éléments:

sed 's/[[:space:]]*[^[:space:]]*$//' file

awk '{sub(/[[:space:]]*[^[:space:]]*$/,"")}1' file
1
Ed Morton

Si le délimiteur est toujours un seul caractère (deux délimiteurs consécutifs ou plus désignent des champs vides), vous pouvez head juste la première ligne de votre fichier d'entrée, compter les délimiteurs (n délimiteurs signifie nombre des champs est n+1) puis utilisez cut pour imprimer à partir du 1st champ jusqu'au nth champ (avant-dernier), par exemple avec entrée délimitée par des tabulations:

n=$(head -n 1 infile | tr -dc \\t | tr \\t \\n | wc -l)
cut -f1-$n infile > outfile

ou par ex. avec un fichier csv:

n=$(head -n 1 infile | tr -dc , | tr , \\n | wc -l)
cut -d, -f1-$n infile > outfile

J'exécuterai quelques benchmarks plus tard si j'ai le temps, mais avec une énorme contribution, je pense que cette solution devrait être plus rapide que d'autres solutions qui utilisent l'expression régulière car celle-ci effectue un traitement minimal sur la première ligne pour obtenir le non. des champs, puis utilise cut qui est optimisé pour ce travail.

1
don_crissti

Pour les personnes qui ont un problème similaire mais avec des séparateurs de champs différents, cette méthode awk préservera correctement le séparateur de champs:

$ cat file 
foo.bar.baz
baz.bar.foo
$ awk -F'.' 'sub(FS $NF,x)' file
foo.bar
baz.bar
0
htaccess

Utilisation de vim:

Ouvrir un fichier dans vim

vim <filename> 

Allez à la première ligne, juste au cas où le curseur serait placé ailleurs.

gg

Créez une macro nommée "q" qq, qui va à l'arrière de la ligne actuelle $, puis retourne au dernier espace F (F majuscule, suivi de l'ESPACE littéral) puis supprimez de la position actuelle jusqu'à la fin de la ligne D descendez à la ligne suivante j et arrêtez l'enregistrement des macros avec q.

qq$F Djq

Maintenant, nous pouvons répéter notre macro avec @q pour chaque ligne.
Nous pouvons également appuyer sur @@ pour répéter la dernière macro ou encore plus facilement:

99@q

pour répéter la macro 99 fois.
Remarque: Le nombre ne doit pas correspondre exactement aux lignes.

0
cee