Afficher deux fichiers côte à côte


94

Comment deux fichiers texte non triés de différentes longueurs peuvent-ils être affichés côte à côte (en colonnes) dans unshell

Donné one.txtet 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

Afficher:

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

                                    skipped a line

paste one.txt two.txtfait presque l'affaire mais n'aligne pas bien les colonnes car il imprime juste un onglet entre les colonnes 1 et 2. Je sais comment faire avec emacs et vim mais je veux que la sortie soit affichée sur stdout pour la tuyauterie ect.

La solution que j'ai proposée utilise sdiff, puis des tuyaux à sed pour supprimer la sortie sdiffajoute.

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

Je pourrais créer une fonction et la coller dans mon .bashrcmais sûrement une commande pour cela existe déjà (ou une solution plus propre potentiellement)?


Pas dans un shell, mais il convient de le mentionner: utilisez meld !
fedorqui 'SO arrêtez de nuire'

Réponses:


166

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

pr -m -t one.txt two.txt

les sorties:

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

                                    skipped a line

Voir également:


15
Parfait! Je savais que quelque chose existerait, dont on n'avait jamais entendu parler prauparavant. J'ai essayé avec 3 fichiers et la sortie a été tronquée mais l' -woption a résolu cela. Bonne réponse.
Chris Seymour

5
@sudo_o: Heureux d'aider, coreutils regorge de pierres précieuses
Hasturkun

1
Existe-t-il un moyen pour pr de détecter automatiquement la largeur de l'écran?
Matt

2
@Matt: Vous pouvez utiliser $COLUMNS, qui devrait être fourni par le shell.
Hasturkun

1
Lorsqu'il est utilisé pour imprimer deux fichiers côte à côte, prcoupe la fin des longues lignes. Y a-t-il un moyen de le faire envelopper les lignes?
molnarg

32

Pour développer un peu la réponse de @Hasturkun : par défaut prn'utilise que 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 shell stockeront (et mettront à jour) la largeur d'écran de votre terminal dans la $COLUMNSvariable d'environnement, nous transmettons donc simplement cette valeur à prpour l'utiliser pour le paramètre de largeur de sortie.

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

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

Donc non: prlui - même ne peut pas détecter la largeur de l'écran, mais nous aidons un peu en passant la largeur du terminal via l' -woption.


7

Si vous savez que les fichiers d'entrée n'ont pas d'onglets, utiliser expandsimplifie la réponse de @oyss :

paste one.txt two.txt | expand --tabs=50

S'il peut y avoir des onglets dans les fichiers d'entrée, vous pouvez toujours développer en premier:

paste <(expand one.txt) <(expand two.txt) | expand --tabs=50

6
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])}
}'

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


1
Je ne l'ai jamais dit, mais si je veux afficher deux fichiers côte à côte de temps en temps, faire diff -y one.txt two.txtun meilleur travail que paste one.txt two.txtet supprimer les caractères supplémentaires diffs qui sont affichés avec sedest trivial en comparaison avec l'écriture / la mémorisation d'un awkscript. Même avec les deux fonctions en .bash_rcplus! = Meilleur, plus lisible, plus rapide .. quel est l'avantage ici?
Chris Seymour

2

supprimer dynamiquement le comptage de longueur de champ 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 qui ne peut être évité quelle que soit la méthode que vous choisissez.

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

2

Si vous souhaitez connaître la différence réelle entre deux fichiers côte à côte, utilisez diff -y:

diff -y file1.cf file2.cf

Vous pouvez également définir une largeur de sortie à l'aide de l' -W, --width=NUMoption:

diff -y -W 150 file1.cf file2.cf

et pour que diffla sortie de la colonne corresponde à votre fenêtre de terminal actuelle:

diff -y -W $COLUMNS file1.cf file2.cf

2

Il existe un sedmoyen:

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 , 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 prest la plus précise !) :

Avantage de sedpluspr

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, à titre d'exemple, pour marquer des 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

1

Retrouvez ci-dessous une solution basée sur python.

import sys

# Specify the number of spaces between the columns
S = 4

# Read the first file
l0 = open( sys.argv[1] ).read().split('\n')

# Read the second file
l1 = open( sys.argv[2] ).read().split('\n')

# Find the length of the longest line of the first file
n = len(max(l0, key=len))

# Print the lines
for i in  xrange( max( len(l0), len(l1) ) ):

    try:
        print l0[i] + ' '*( n - len(l0[i]) + S) + l1[i]
    except:
        try:
            print ' ' + ' '*( n - 1 + S) + l1[i]
        except:
            print l0[i]

Exemple

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

                                 skipped a line

0
diff -y <file1> <file2>


[root /]# cat /one.txt
Pomme
poire
ligne plus longue que les deux derniers
dernière ligne
[root /]# cat /two.txt
Le renard brun rapide..
toto
bar
Linux
[root@RHEL6-64 /]# diff -y one.txt two.txt
pomme | Le renard brun rapide..
poire | toto
ligne plus longue que les deux derniers | bar
dernière ligne | Linux

sdiffest diff -yque je discute dans la question.
Chris Seymour le

Oui, c'est vrai ... il a été mentionné pour montrer un autre paramètre de commande / indicateur de le faire.
iAdhyan

Mais il ne répond pas aux questions diffajoute des caractères entre les deux fichiers.
Chris Seymour
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.