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

25

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
zara
la source
Il existe de nombreuses façons de le faire .. veuillez ajouter un exemple et la sortie attendue de celui-ci ..
heemayl
@heemayl ok je l'ai fait
zara
Merci ... les colonnes sont-elles séparées par des tabulations ou par des espaces?
heemayl
@heemayl space is deliminator
zara

Réponses:

43

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 à la deuxième partie. NFest 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ù NFest décrémentée) ne se produit que si elle NFn'est pas 0.

La deuxième partie (soit NF-=1 NF--ou --NF) en soustrait simplement une de la NFvariable. Cela empêche l'impression du dernier champ, car lorsque vous modifiez un champ (en supprimant le dernier champ dans ce cas), awkreconstruisez $0, concaténez tous les champs séparés par un espace par défaut. $0ne 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 awkexpression est évaluée à true sans aucune action associée, l'action awkpar défaut est print $0.

cuonglm
la source
@JJoao: Ah, merci, j'ai oublié --. Une note, actuellement, vous avez besoin ;1pour la conformité POSIX.
cuonglm
Mon instinct initial serait d'utiliser une boucle for, mais c'est beaucoup plus concis et intelligent.
Sergiy Kolodyazhnyy
5
Il convient de noter que si vous utilisez un délimiteur autre que celui par défaut, vous devrez apporter quelques modifications. En supposant que ,votre délimiteur:awk -F',' 'BEGIN { OFS = FS }; NF { NF -= 1 }; 1' < in > out
M. Llama
1
L'effet de décrémentation de NF est un comportement indéfini par POSIX - vous obtiendrez une sortie différente en fonction de l'awk que vous utilisez. Certains awks supprimeront le dernier champ comme vous le souhaitez, certains ne feront rien du tout, et d'autres pourraient signaler une erreur de syntaxe ou autre chose.
Ed Morton
16

Utilisation grepavec 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
heemayl
la source
1
@ramin Sure..pouvez-vous s'il vous plaît le poser comme une nouvelle question (c'est ainsi que fonctionne ce site) :)
heemayl
@ramin Cela vous donne-t-il une restriction de temps ou un avertissement?
heemayl
ça dit que c'est hors de question!
zara
@ramin Ok..mettez-moi en contact avec un administrateur, peut-être qu'ils peuvent vous aider avec cela..btw avez-vous vérifié un ancien QA concernant votre question? c'est une possibilité que la question soit déjà posée et répondue ..
heemayl
3
Ne posez pas de questions super basiques comme " comment renommer un nom de fichier sous Linux ". Utilisez Google.
Christoffer Hammarström
11

Utilisation de Perl:

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

Utiliser rev+ cut:

rev in | cut -d ' ' -f 2- | rev
kos
la source
5

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
Traumatisme numérique
la source
1

Si le délimiteur est toujours un seul caractère (donc deux délimiteurs consécutifs ou plus désignent des champs vides), vous pouvez headsimplement la première ligne de votre fichier d'entrée, compter les délimiteurs ( ndélimiteurs signifie que le nombre de champs est n+1) puis utiliser cutpour imprimer à partir du 1champ st jusqu'au nchamp e (avant-dernier), par exemple avec une 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 exemple 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 cutce qui est optimisé pour ce travail.

don_crissti
la source
1

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

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

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

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 par ESPACE littéral) puis supprimez de la position actuelle jusqu'à la fin de la ligne, Ddescendez à la ligne suivante jet arrêter l'enregistrement de macro avec q.

qq$F Djq

Maintenant, nous pouvons répéter notre macro avec @qpour 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.

cee
la source
0

Pour les personnes qui ont un problème similaire mais avec des séparateurs de champs différents, cette awkméthode 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
htaccess
la source