Réponses:
Pour la cut(1)
page de manuel:
Utilisez un et un seul parmi -b, -c ou -f. Chaque LISTE est composée d'une plage ou de plusieurs plages séparées par des virgules. L'entrée sélectionnée est écrite dans le même ordre où elle est lue et est écrite exactement une fois.
Il atteint d'abord le champ 1, de sorte qu'il est imprimé, suivi du champ 2.
Utilisez à la awk
place:
awk '{ print $2 " " $1}' file.txt
FS
est une option, OFS
est une variable. egawk -v OFS=";" -F"\t" '{print $2,$1}'
| sed 's/\r//' |
avant de passer àawk
awk '{print $4 "\t" $2 "\t" $6 "\t" $7}' file
Vous pouvez également combiner cut
et paste
:
paste <(cut -f2 file.txt) <(cut -f1 file.txt)
via les commentaires: Il est possible d'éviter les bashismes et de supprimer une instance de coupe en faisant:
paste file.txt file.txt | cut -f2,3
cut
fonctionne très bien pour les colonnes de longueur variable tant que vous avez un séparateur de colonne unique.
bash
isms et de supprimer une instance de cut
en faisant: paste file.txt file.txt | cut -f2,3
en utilisant juste la coque,
while read -r col1 col2
do
echo $col2 $col1
done <"file"
"$col2"
et "$col1"
- il pourrait y avoir des métacaractères shell ou d'autres manigances dans les données.
Vous pouvez utiliser Perl pour cela:
perl -ane 'print "$F[1] $F[0]\n"' < file.txt
L'avantage d'exécuter perl est que (si vous connaissez Perl) vous pouvez faire beaucoup plus de calculs sur F que de réorganiser les colonnes.
perl -ae print
fonctionne comme cat
pour moi
Utilisation join
:
join -t $'\t' -o 1.2,1.1 file.txt file.txt
Remarques:
-t $'\t'
Dans GNU join
le plus intuitif -t '\t'
sans les $
échecs, ( coreutils v8.28 et antérieurs?); c'est probablement un bogue qu'une solution de contournement comme $
devrait être nécessaire. Voir: unix join separator char .
join
a besoin de deux noms de fichiers, même s'il n'y a qu'un seul fichier en cours de traitement. Utiliser deux fois le même nom permet d' join
effectuer l'action souhaitée.
Pour les systèmes à faibles ressources, il join
offre une empreinte plus petite que certains des outils utilisés dans d'autres réponses:
wc -c $(realpath `which cut join sed awk perl`) | head -n -1
43224 /usr/bin/cut
47320 /usr/bin/join
109840 /bin/sed
658072 /usr/bin/gawk
2093624 /usr/bin/perl
Je viens de travailler sur quelque chose de très similaire, je ne suis pas un expert mais je pensais partager les commandes que j'ai utilisées. J'avais un csv multi-colonnes dont je n'avais besoin que de 4 colonnes, puis je devais les réorganiser.
Mon fichier était pipe '|' délimité mais qui peut être échangé.
LC_ALL=C cut -d$'|' -f1,2,3,8,10 ./file/location.txt | sed -E "s/(.*)\|(.*)\|(.*)\|(.*)\|(.*)/\3\|\5\|\1\|\2\|\4/" > ./newcsv.csv
Certes, c'est vraiment rugueux et prêt, mais il peut être modifié pour convenir!
Utilisation de sed
Utilisez sed avec les sous-expressions imbriquées des expressions régulières de base pour capturer et réorganiser le contenu de la colonne. Cette approche est la mieux adaptée lorsqu'il y a un nombre limité de coupes pour réorganiser les colonnes, comme dans ce cas.
L'idée de base est d'entourer les parties intéressantes du motif de recherche avec \(
et \)
, qui peuvent être lues dans le motif de remplacement avec \#
où #
représente la position séquentielle de la sous-expression dans le motif de recherche.
Par exemple:
$ echo "foo bar" | sed "s/\(foo\) \(bar\)/\2 \1/"
donne:
bar foo
Le texte en dehors d'une sous-expression est analysé mais pas conservé pour la lecture dans la chaîne de remplacement.
Bien que la question n'ait pas abordé les colonnes à largeur fixe, nous en discuterons ici car c'est une mesure digne de toute solution posée. Pour simplifier, supposons que le fichier soit délimité par des espaces bien que la solution puisse être étendue pour d'autres délimiteurs.
Espaces réduits
Pour illustrer l'utilisation la plus simple, supposons que plusieurs espaces peuvent être réduits en espaces simples et que les valeurs de la deuxième colonne se terminent par EOL (et non par un espace).
Fichier:
bash-3.2$ cat f
Column1 Column2
str1 1
str2 2
str3 3
bash-3.2$ od -a f
0000000 C o l u m n 1 sp sp sp sp C o l u m
0000020 n 2 nl s t r 1 sp sp sp sp sp sp sp 1 nl
0000040 s t r 2 sp sp sp sp sp sp sp 2 nl s t r
0000060 3 sp sp sp sp sp sp sp 3 nl
0000072
Transformer:
bash-3.2$ sed "s/\([^ ]*\)[ ]*\([^ ]*\)[ ]*/\2 \1/" f
Column2 Column1
1 str1
2 str2
3 str3
bash-3.2$ sed "s/\([^ ]*\)[ ]*\([^ ]*\)[ ]*/\2 \1/" f | od -a
0000000 C o l u m n 2 sp C o l u m n 1 nl
0000020 1 sp s t r 1 nl 2 sp s t r 2 nl 3 sp
0000040 s t r 3 nl
0000045
Préservation des largeurs de colonne
Étendons maintenant la méthode à un fichier avec des colonnes de largeur constante, tout en permettant aux colonnes d'être de largeurs différentes.
Fichier:
bash-3.2$ cat f2
Column1 Column2
str1 1
str2 2
str3 3
bash-3.2$ od -a f2
0000000 C o l u m n 1 sp sp sp sp C o l u m
0000020 n 2 nl s t r 1 sp sp sp sp sp sp sp 1 sp
0000040 sp sp sp sp sp nl s t r 2 sp sp sp sp sp sp
0000060 sp 2 sp sp sp sp sp sp nl s t r 3 sp sp sp
0000100 sp sp sp sp 3 sp sp sp sp sp sp nl
0000114
Transformer:
bash-3.2$ sed "s/\([^ ]*\)\([ ]*\) \([^ ]*\)\([ ]*\)/\3\4 \1\2/" f2
Column2 Column1
1 str1
2 str2
3 str3
bash-3.2$ sed "s/\([^ ]*\)\([ ]*\) \([^ ]*\)\([ ]*\)/\3\4 \1\2/" f2 | od -a
0000000 C o l u m n 2 sp C o l u m n 1 sp
0000020 sp sp nl 1 sp sp sp sp sp sp sp s t r 1 sp
0000040 sp sp sp sp sp nl 2 sp sp sp sp sp sp sp s t
0000060 r 2 sp sp sp sp sp sp nl 3 sp sp sp sp sp sp
0000100 sp s t r 3 sp sp sp sp sp sp nl
0000114
Enfin, bien que l'exemple de la question n'ait pas de chaînes de longueur inégale, cette expression sed prend en charge ce cas.
Fichier:
bash-3.2$ cat f3
Column1 Column2
str1 1
string2 2
str3 3
Transformer:
bash-3.2$ sed "s/\([^ ]*\)\([ ]*\) \([^ ]*\)\([ ]*\)/\3\4 \1\2/" f3
Column2 Column1
1 str1
2 string2
3 str3
bash-3.2$ sed "s/\([^ ]*\)\([ ]*\) \([^ ]*\)\([ ]*\)/\3\4 \1\2/" f3 | od -a
0000000 C o l u m n 2 sp C o l u m n 1 sp
0000020 sp sp nl 1 sp sp sp sp sp sp sp s t r 1 sp
0000040 sp sp sp sp sp nl 2 sp sp sp sp sp sp sp s t
0000060 r i n g 2 sp sp sp nl 3 sp sp sp sp sp sp
0000100 sp s t r 3 sp sp sp sp sp sp nl
0000114
Comparaison avec d'autres méthodes de réorganisation des colonnes sous shell
Étonnamment pour un outil de manipulation de fichiers, awk n'est pas bien adapté pour couper d'un champ à la fin d'un enregistrement. Dans sed, cela peut être accompli en utilisant des expressions régulières, par exemple \(xxx.*$\)
où xxx
est l'expression correspondant à la colonne.
L'utilisation de sous-shell coller et couper devient délicate lors de l'implémentation de scripts shell internes. Le code qui fonctionne à partir de la ligne de commande ne parvient pas à être analysé lorsqu'il est introduit dans un script shell. Au moins c'était mon expérience (qui m'a poussé à cette approche).
Extension de la réponse de @Met, également en utilisant Perl:
Si l'entrée et la sortie sont délimitées par TAB:
perl -F'\t' -lane 'print join "\t", @F[1, 0]' in_file
Si l'entrée et la sortie sont séparées par des espaces:
perl -lane 'print join " ", @F[1, 0]' in_file
Ici,
-e
indique à Perl de rechercher le code en ligne, plutôt que dans un fichier de script séparé,
-n
lit l'entrée 1 ligne à la fois,
-l
supprime le séparateur d'enregistrement d'entrée ( \n
sur * NIX) après avoir lu la ligne (similaire à chomp
), et ajoute la sortie séparateur d'enregistrement ( \n
sur * NIX) à chacun print
,
-a
divise la ligne d'entrée sur les espaces en tableau @F
,
-F'\t'
en combinaison avec -a
divise la ligne d'entrée sur les TAB, au lieu des espaces en tableau @F
.
@F[1, 0]
est le tableau composé des 2e et 1er éléments du tableau @F
, dans cet ordre. N'oubliez pas que les tableaux en Perl sont indexés à zéro, tandis que les champs dans cut
sont indexés à 1. Les champs de @F[0, 1]
sont donc les mêmes que ceux de cut -f1,2
.
Notez qu'une telle notation permet une manipulation plus flexible de l'entrée que dans certaines autres réponses publiées ci-dessus (ce qui est bien pour une tâche simple). Par exemple:
# reverses the order of fields:
perl -F'\t' -lane 'print join "\t", reverse @F' in_file
# prints last and first fields only:
perl -F'\t' -lane 'print join "\t", @F[-1, 0]' in_file
cut
ne pas prendre en charge cette commande de réorganisation intuitive. Quoi qu'il en soit, une autre astuce: vous pouvez utiliserawk
les options-FS
et-OFS
pour utiliser des séparateurs de champs d'entrée et de sortie personnalisés (comme-d
et--output-delimiter
pourcut
).