web-dev-qa-db-fra.com

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

J'essaie d'extraire un certain (le quatrième) champ du flux de texte ajusté en fonction de l'espace basé sur des colonnes. J'essaie d'utiliser la commande 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 à travers 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 cut et plusieurs délimiteurs de manière native?

298
mbaitoff

Essayer:

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

Depuis la page de manuel tr:

 - s, --squeeze-repeats remplace chaque séquence d'entrée d'un caractère répété 
 répertorié dans SET1 par une seule occurrence 
 de ce caractère 
532
kev

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

Laissez-moi cependant passer en revue toutes les combinaisons possibles pour les futurs lecteurs. Les explications sont à la section Test.

tr | Couper

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

Des tests

Étant donné ce fichier, testons 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 | Couper

$ 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

Ceci lit les champs séquentiellement. En utilisant _, nous indiquons qu'il s'agit d'une variable jetable en tant que "variable indésirable" permettant d'ignorer ces champs. De cette façon, nous stockons $myfield comme 4ème champ du fichier, quels que soient les espaces entre eux.

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

sed

Ceci intercepte trois groupes d'espaces et aucun espace avec ([^ ]*[ ]*){3}. Ensuite, il attrape ce qui vient jusqu'à un espace en tant que 4ème champ, qu'il soit finalement imprimé avec \1.

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

solution la plus courte/la plus conviviale

Après être devenu frustré par les trop nombreuses limitations de cut, j’ai écrit mon propre substitut, que j’ai appelé cuts pour "couper sur les stéroïdes".

cut fournit ce qui est probablement la solution la plus minimaliste à ce problème et à de nombreux autres problèmes de couper/coller liés .

Un exemple parmi tant d’autres abordant cette question particulière:

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

$ cuts 2 text.txt
2
2

cuts prend en charge:

  • détection automatique des délimiteurs de champ les plus courants dans les fichiers (+ possibilité de remplacer les valeurs par défaut)
  • délimiteurs assortis multi-caractères, caractères mixtes et regex
  • extraction de colonnes de plusieurs fichiers avec des délimiteurs mixtes
  • décalages à partir de la fin de la ligne (avec des nombres négatifs) en plus du début de la ligne
  • collage automatique des colonnes côte à côte (inutile d'appeler paste séparément)
  • support pour la réorganisation des champs
  • un fichier de configuration où les utilisateurs peuvent modifier leurs préférences personnelles
  • grande emphase sur la convivialité et la dactylographie minimale requise

et beaucoup plus. Aucun de ces éléments 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/

25
arielf

Ce Perl one-liner montre à quel point Perl est lié à awk:

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

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

3
Chris Koknat

Avec les versions de cut à ma connaissance, non, ce n'est pas possible. cut est principalement utile pour analyser des fichiers dont le séparateur n'est pas un espace (par exemple /etc/passwd) et qui ont un nombre fixe de champs. Deux séparateurs en ligne signifient un champ vide, ce qui vaut également pour les espaces.

3
Benoit