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


309

J'essaie d'extraire un certain (le quatrième) champ du flux de texte ajusté en fonction de l'espace. J'essaie d'utiliser la cutcommande de la manière suivante:

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

Malheureusement, cutne traite pas plusieurs espaces comme un 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 gérer cutet plusieurs délimiteurs en natif?


12
AWK est la voie à suivre.
pause jusqu'à nouvel ordre.

Réponses:


546

Essayer:

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

Depuis la trpage de manuel:

-s, --squeeze-repeats remplacent chaque séquence d'entrée d'un caractère répété
                        qui est répertorié dans SET1 avec une seule occurrence
                        de ce personnage

24
Pas besoin catici. Vous pouvez passer < text.txtdirectement à tr. en.wikipedia.org/wiki/Cat_%28Unix%29#Useless_use_of_cat
arielf

1
Pas sûr que ce soit plus simple, mais vous allez fusionner, vous pouvez renoncer aux coupes -det traduire directement de plusieurs caractères à l'onglet. Par exemple: Je suis venu ici à la recherche d'un moyen d'exporter automatiquement mon affichage:who am i | tr -s ' ()' '\t' | cut -f5
Leo

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

-1 AVERTISSEMENT: CE N'EST PAS LA MÊME CHOSE QUE LE TRAITEMENT DES DÉLIMÈTRES SÉQUENTIELS COMME UN. Comparer echo "a b c" | cut -d " " -f2-,echo "a b c" | tr -s " " | cut -d " " -f2-
user541686

96

Comme vous le dites dans votre question, awkc'est vraiment la voie à suivre. Utiliser cutest possible avec tr -spour serrer les espaces, comme le montre la réponse de kev .

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

tr | Couper

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

awk

awk '{print $4}' file

frapper

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

sed

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

Les tests

Compte tenu de 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

frapper

Cela lit les champs de manière séquentielle. En utilisant, _nous indiquons qu'il s'agit d'une variable jetable en tant que "variable indésirable" pour ignorer ces champs. De cette façon, nous stockons en $myfieldtant que 4ème champ dans le fichier, peu importe 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

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

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

2
awkn'est pas seulement élégant et simple, il est également inclus dans VMware ESXi, où il trmanque.
user121391

2
@ user121391 encore une autre raison d'utiliser awk!
fedorqui 'SO arrête de nuire'

@fedorqui Je n'ai jamais entendu parler du trait de soulignement comme "variable indésirable". Pouvez-vous fournir plus d'informations / références à ce sujet?
BryKKan

1
@BryKKan Je l'ai appris dans Greg's Comment lire un fichier (flux de données, variable) ligne par ligne (et / ou champ par champ)? : Certaines personnes utilisent la variable jetable _ comme "variable indésirable" pour ignorer les champs. Il (ou en fait n'importe quelle variable) peut également être utilisé plus d'une fois dans une seule readcommande, si nous ne nous soucions pas de ce qu'il contient . Cela peut être n'importe quoi, c'est juste que cela est devenu en quelque sorte standard au lieu de junk_varou whatever:)
fedorqui 'SO arrêtez de nuire'

25

solution la plus courte / la plus conviviale

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

Les coupes fournissent ce qui est probablement la solution la plus minimaliste à cela et à de nombreux autres problèmes de couper / coller.

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 les soutiens:

  • détection automatique des délimiteurs de champ les plus courants dans les fichiers (+ possibilité de remplacer les valeurs par défaut)
  • délimiteurs appariés multi-char, mixed-char et regex
  • extraction de colonnes de plusieurs fichiers avec des délimiteurs mixtes
  • décalages à partir 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'appeler pasteséparément)
  • prise en charge de la réorganisation des champs
  • un fichier de configuration où les utilisateurs peuvent modifier leurs préférences personnelles
  • grande importance accordée à la convivialité et à la saisie minimaliste requise

et beaucoup plus. Aucun n'est fourni par la norme cut.

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

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


4

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

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

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


3

Avec les versions que cutje connais, non, ce n'est pas possible. cutest principalement utile pour analyser des fichiers où le séparateur n'est pas un espace (par exemple /etc/passwd) et qui ont un nombre fixe de champs. Deux séparateurs d'affilée signifient un champ vide, et cela vaut également pour les espaces blancs.

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.