126 votes

Afficher deux fichiers côte à côte

Comment afficher côte à côte deux fichiers texte non triés de longueurs différentes ? (en colonnes) dans un shell

Étant donné que one.txt y two.txt :

$ cat one.txt
apple
pear
longer line than the last two
last line

$ cat two.txt
The quick brown fox..
foo
bar 
linux

skipped a line

Affichez :

apple                               The quick brown fox..
pear                                foo
longer line than the last two       bar 
last line                           linux

                                    skipped a line

paste one.txt two.txt fait presque l'affaire mais n'aligne pas les colonnes correctement car il n'imprime qu'une tabulation entre les colonnes 1 et 2. Je sais comment le faire avec emacs et vim mais je veux que la sortie soit affichée dans stdout pour le piping ect.

La solution que j'ai trouvée utilise sdiff puis passe à sed pour enlever la sortie sdiff ajoute.

sdiff one.txt two.txt | sed -r 's/[<>|]//;s/(\t){3}//'

Je pourrais créer une fonction et la mettre dans mon .bashrc mais il existe sûrement déjà une commande pour cela (ou une nettoyant potentiellement une solution) ?

1 votes

Pas dans un shell, mais cela vaut la peine d'être mentionné : utiliser se mélanger !

219voto

Hasturkun Points 18653

Vous pouvez utiliser pr pour ce faire, en utilisant le -m pour fusionner les fichiers, un par colonne, et -t pour omettre les en-têtes, par exemple.

pr -m -t one.txt two.txt

sorties :

apple                               The quick brown fox..
pear                                foo
longer line than the last two       bar
last line                           linux

                                    skipped a line

Voir aussi :

20 votes

Parfait ! Je savais qu'il y aurait quelque chose, mais je n'ai jamais entendu parler de ce produit. pr avant. J'ai essayé avec 3 fichiers et la sortie était tronquée mais la -w a résolu le problème. Bonne réponse.

5 votes

@sudo_o : Heureux d'aider, coreutils est plein de gems.

1 votes

Y a-t-il un moyen pour pr de détecter automatiquement la largeur de l'écran ?

47voto

pvandenberk Points 1199

Pour développer un peu plus sur @Hasturkun Réponse de la Commission : par défaut pr utilise seulement 72 colonnes pour sa sortie, mais il est relativement facile de lui faire utiliser toutes les colonnes disponibles de votre fenêtre de terminal :

pr -w $COLUMNS -m -t one.txt two.txt

La plupart des coquilles stockent (et mise à jour) la largeur d'écran de votre terminal dans le champ $COLUMNS Nous passons donc cette valeur à la variable shell pr à utiliser pour le paramètre de largeur de sa sortie.

Cela répond également à @Matt de la question :

Y a-t-il un moyen pour pr de détecter automatiquement la largeur de l'écran ?

Donc, non : pr lui-même ne peut pas détecter la largeur de l'écran, mais nous l'aidons un peu en lui transmettant la largeur du terminal via sa fonction -w opción.

Notez que $COLUMNS est une variable de l'interpréteur de commandes, pas une variable d'environnement, donc elle n'est pas exportée vers les processus enfants, et donc l'approche ci-dessus ne fonctionnera probablement pas dans les scripts, seulement dans les ATS interactifs... voir Variables d'environnement LINES et COLUMNS perdues dans un script. pour des approches alternatives.

7voto

Barmar Points 135986
paste one.txt two.txt | awk -F'\t' '{
    if (length($1)>max1) {max1=length($1)};
    col1[NR] = $1; col2[NR] = $2 }
    END {for (i = 1; i<=NR; i++) {printf ("%-*s     %s\n", max1, col1[i], col2[i])}
}'

Utilisation de * dans une spécification de format vous permet de fournir la longueur du champ de manière dynamique.

3voto

F. Hauri Points 5893

Il existe un sed manière :

f1width=$(wc -L <one.txt)
f1blank="$(printf "%${f1width}s" "")"
paste one.txt two.txt |
    sed "
        s/^\(.*\)\t/\1$f1blank\t/;
        s/^\(.\{$f1width\}\) *\t/\1 /;
    "

Sous bash vous pouvez utiliser printf -v :

f1width=$(wc -L <one.txt)
printf -v f1blank "%${f1width}s"
paste one.txt two.txt |
    sed "s/^\(.*\)\t/\1$f1blank\t/;
         s/^\(.\{$f1width\}\) *\t/\1 /;"

(Bien sûr, la solution de @Hasturkun's <code>pr</code> est le <strong>la plus précise </strong>!) :

Avantage de sed en pr

Vous pouvez choisir finement la largeur de séparation et/ou les séparateurs :

f1width=$(wc -L <one.txt)
(( f1width += 4 ))         # Adding 4 spaces
printf -v f1blank "%${f1width}s"
paste one.txt two.txt |
    sed "s/^\(.*\)\t/\1$f1blank\t/;
         s/^\(.\{$f1width\}\) *\t/\1 /;"

Ou, par exemple, pour marquer les lignes contenant line :

f1width=$(wc -L <one.txt)
printf -v f1blank "%${f1width}s"
paste one.txt two.txt |
    sed "s/^\(.*\)\t/\1$f1blank\t/;
  /line/{s/^\(.\{$f1width\}\) *\t/\1 |ln| /;ba};
         s/^\(.\{$f1width\}\) *\t/\1 |  | /;:a"

rendra :

apple                         |  | The quick brown fox..
pear                          |  | foo
longer line than the last two |ln| bar 
last line                     |ln| linux
                              |  | 
                              |ln| skipped a line

0 votes

bash f1width=$(wc -L <one.txt) printf -v f1blank "%${f1width}s" paste one.txt two.txt | sed "s/^\(.*\)\t/\1$f1blank\t/; /line/{s/^\(.\{$f1width\}\) *\t/\1 |ln| /;ba}; s/^\(.\{$f1width\}\) *\t/\1 | | /;:a" Une solution intéressante, très utile dans d'autres contextes.

2voto

oyss Points 364

Enlever le comptage dynamique de la longueur des champs de la réponse de Barmar en fera une commande beaucoup plus courte....mais vous avez toujours besoin d'au moins un script pour terminer le travail, ce qui ne pourrait être évité quelle que soit la méthode choisie.

paste one.txt two.txt |awk -F'\t' '{printf("%-50s %s\n",$1,$2)}'

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