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?
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
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 -s ' ' < file | cut -d' ' -f4
awk '{print $4}' file
while read -r _ _ _ myfield _
do
echo "forth field: $myfield"
done < file
sed -r 's/^([^ ]*[ ]*){3}([^ ]*).*/\2/' file
É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
$ 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 '{print $4}' a
1
2
3
4
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
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
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:
paste
séparément)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/
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
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.