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
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-=1
NF--
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
.
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
Utilisation de Perl:
Perl -lane '$,=" ";pop(@F);print(@F)' in
Utilisation de rev
+ cut
:
rev in | cut -d ' ' -f 2- | rev
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
Vous pouvez utiliser l'un ou l'autre de ces éléments:
sed 's/[[:space:]]*[^[:space:]]*$//' file
awk '{sub(/[[:space:]]*[^[:space:]]*$/,"")}1' file
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 1
st champ jusqu'au n
th 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.
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
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.