320 votes

Comment faire pour que la commande 'cut' traite les mêmes délimiteurs séquentiels comme un seul ?

J'essaie d'extraire un certain champ (le quatrième) d'un flux de texte basé sur des colonnes et ajusté par des espaces. J'essaie d'utiliser la fonction cut de la manière suivante :

cat text.txt | cut -d " " -f 4

Malheureusement, cut ne traite pas plusieurs espaces comme un seul délimiteur. J'aurais pu passer par awk

awk '{ printf $4; }'

ou sed

sed -E "s/[[:space:]]+/ /g"

pour réduire les espaces, mais j'aimerais savoir s'il existe un moyen de traiter les cut et plusieurs délimiteurs de manière native ?

13 votes

AWK est la voie à suivre.

0 votes

566voto

kev Points 41855

Essayez :

tr -s ' ' <text.txt | cut -d ' ' -f4

De la tr page de manuel :

\-s, --squeeze-repeats   replace each input sequence of a repeated character
                        that is listed in SET1 with a single occurrence
                        of that character

25 votes

Pas besoin de cat ici. Vous pourriez passer < text.txt directement à tr . fr.wikipedia.org/wiki/Cat_%28Unix%29#Useless_use_of_cat

1 votes

Je ne suis pas sûr que ce soit plus simple, mais si vous allez fusionner, vous pouvez renoncer aux coupures. -d et traduire directement de multiples caractères en tabulation. Par exemple : Je suis venu ici pour chercher un moyen d'exporter automatiquement mon affichage : who am i | tr -s ' ()' '\t' | cut -f5

0 votes

Cela ne supprime pas les espaces blancs de début et de fin (qui peuvent être ou non souhaités, mais qui ne le sont généralement pas), contrairement à la solution awk. La solution awk est également beaucoup plus lisible et moins verbeuse.

98voto

fedorqui Points 42938

Comme vous le commentez dans votre question, awk est vraiment la voie à suivre. Pour utiliser cut est possible avec tr -s pour comprimer les espaces, comme réponse de kev montre.

Permettez-moi cependant de passer en revue toutes les combinaisons possibles pour les futurs lecteurs. Les explications se trouvent dans la section Test.

tr | cut

tr -s ' ' < file | cut -d' ' -f4

awk

awk '{print $4}' file

bash

while read -r _ _ _ myfield _
do
   echo "forth field: $myfield"
done < file

sed

sed -r 's/^([^ ]*[ ]*){3}([^ ]*).*/\2/' file

Tests

Avec ce fichier, nous allons tester les commandes :

$ cat a
this   is    line     1 more text
this      is line    2     more text
this    is line 3     more text
this is   line 4            more    text

tr | cut

$ cut -d' ' -f4 a
is
                        # it does not show what we want!

$ tr -s ' ' < a | cut -d' ' -f4
1
2                       # this makes it!
3
4
$

awk

$ awk '{print $4}' a
1
2
3
4

bash

Cette opération lit les champs de manière séquentielle. En utilisant _ nous indiquons qu'il s'agit d'une variable jetable comme une "variable poubelle" pour ignorer ces champs. De cette façon, nous stockons $myfield comme le 4e champ du fichier, quels que soient les espaces qui les séparent.

$ while read -r _ _ _ a _; do echo "4th field: $a"; done < a
4th field: 1
4th field: 2
4th field: 3
4th field: 4

sed

Cela permet d'attraper trois groupes d'espaces et aucun espace avec ([^ ]*[ ]*){3} . Ensuite, il attrape tout ce qui vient jusqu'à un espace comme 4ème champ, qui est finalement imprimé avec \1 .

$ sed -r 's/^([^ ]*[ ]*){3}([^ ]*).*/\2/' a
1
2
3
4

2 votes

awk n'est pas seulement élégante et simple, elle est également incluse dans VMware ESXi, dans lequel tr est manquant.

2 votes

@user121391 encore une autre raison pour utiliser awk !

0 votes

@fedorqui Je n'ai jamais entendu parler de l'underscore comme d'une "variable indésirable". Pouvez-vous nous donner plus d'informations/de références à ce sujet ?

27voto

arielf Points 704

La solution la plus courte/amicale

Après avoir été frustré par les trop nombreuses limitations de l'application cut j'ai écrit mon propre remplacement, que j'ai appelé cuts pour "couper sur des stéroïdes".

coupe fournit ce qui est probablement la solution la plus minimaliste à ce problème et à celui de l'environnement. beaucoup d'autres problèmes de couper/coller liés.

Un exemple, parmi tant d'autres, pour répondre à cette question particulière :

$ cat text.txt
0   1        2 3
0 1          2   3 4

$ cuts 2 text.txt
2
2

cuts supports :

  • détection automatique des délimiteurs de champs les plus courants dans les fichiers (+ possibilité de modifier les valeurs par défaut)
  • délimiteurs à plusieurs caractères, à caractères mixtes et à correspondance regex
  • extraction de colonnes de plusieurs fichiers avec des délimiteurs mixtes
  • décalage de la fin de la ligne (en utilisant des nombres négatifs) en plus du début de la ligne
  • collage automatique des colonnes côte à côte (pas besoin d'invoquer l'option paste séparément)
  • soutien à la réorganisation des champs
  • un fichier de configuration dans lequel les utilisateurs peuvent modifier leurs préférences personnelles
  • l'accent est mis sur la convivialité et le caractère minimaliste de la saisie.

et bien plus encore. Rien de tout cela n'est fourni par la norme cut .

Voir aussi : https://stackoverflow.com/a/24543231/1296044

Source et documentation (logiciel libre) : http://arielf.github.io/cuts/

4voto

Chris Koknat Points 1732

Cette phrase en Perl montre à quel point Perl est proche de l'awk :

perl -lane 'print $F[3]' text.txt

Cependant, le @F le tableau autosplit commence à l'index $F[0] alors que les champs awk commencent par $1

3voto

Benoit Points 35553

Avec les versions de cut Je connais, non, ce n'est pas possible. cut est principalement utile pour l'analyse des fichiers où le séparateur n'est pas un espace blanc (par exemple /etc/passwd ) et qui ont un nombre fixe de champs. Deux séparateurs consécutifs signifient que le champ est vide, et cela vaut également pour les espaces blancs.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X