Zeigen Sie zwei Dateien nebeneinander an


94

Wie können 2 unsortierte Textdateien unterschiedlicher Länge nebeneinander (in Spalten) in a angezeigt werden?shell

Gegeben one.txtund 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

Anzeige:

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

                                    skipped a line

paste one.txt two.txtmacht fast den Trick, richtet die Spalten aber nicht gut aus, da nur eine Registerkarte zwischen Spalte 1 und 2 gedruckt wird. Ich weiß, wie das mit Emacs und Vim geht, möchte aber, dass die angezeigte Ausgabe für Piping ect stdout angezeigt wird.

Die Lösung, die ich mir ausgedacht habe, verwendet sdiffund leitet dann zu sed, um die Ausgabe zu entfernen sdiff.

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

Ich könnte eine Funktion erstellen und in meine stecken, .bashrcaber sicherlich gibt es bereits einen Befehl dafür (oder möglicherweise eine sauberere Lösung)?


Nicht in einer Muschel, aber erwähnenswert: Verwenden Sie Meld !
Fedorqui 'SO hör auf zu verletzen'

Antworten:


166

Sie können prdies verwenden, indem Sie das -mFlag verwenden, um die Dateien zusammenzuführen, eine pro Spalte, und -tum Überschriften wegzulassen, z.

pr -m -t one.txt two.txt

Ausgänge:

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

                                    skipped a line

Siehe auch:


15
Perfekt! Ich wusste, dass etwas existieren würde, von dem ich noch nie gehört prhatte. Ich habe es mit 3 Dateien versucht und die Ausgabe wurde abgeschnitten, aber die -wOption hat das gelöst. Gute Antwort.
Chris Seymour

5
@sudo_o: Gerne helfen, Coreutils ist voller Edelsteine
Hasturkun

1
Gibt es eine Möglichkeit für pr, die Bildschirmbreite automatisch zu erkennen?
Matt

2
@Matt: Sie könnten verwenden $COLUMNS, was von der Shell bereitgestellt werden sollte.
Hasturkun

1
Wenn Sie zwei Dateien nebeneinander drucken, wird prdas Ende langer Zeilen abgeschnitten. Gibt es eine Möglichkeit, die Zeilen zu umbrechen?
Molnarg

32

Um die Antwort von @Hasturkun ein wenig zu erweitern : Standardmäßig prwerden nur 72 Spalten für die Ausgabe verwendet, aber es ist relativ einfach, alle verfügbaren Spalten Ihres Terminalfensters zu verwenden:

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

Die meisten Shells speichern (und aktualisieren) die Bildschirmbreite Ihres Terminals in der $COLUMNSUmgebungsvariablen. Daher geben wir diesen Wert nur an prdie Breite der Ausgabe weiter.

Dies beantwortet auch die Frage von @Matt :

Gibt es eine Möglichkeit für pr, die Bildschirmbreite automatisch zu erkennen?

Also, nein: prselbst kann die Bildschirmbreite nicht erkennen, aber wir helfen ein bisschen, indem wir die Breite des Terminals über die -wOption übergeben.


7

Wenn Sie wissen, dass die Eingabedateien keine Registerkarten haben, expandvereinfacht die Verwendung von @oyss die Antwort :

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

Wenn die Eingabedateien Registerkarten enthalten könnten, können Sie diese immer zuerst erweitern:

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

Durch die Verwendung *in einer Formatspezifikation können Sie die Feldlänge dynamisch angeben.


1
Nie sagte , es tat, aber wenn ich will an Seite zwei Dateien Seite angezeigt werden gelegentlich dann tut diff -y one.txt two.txteine bessere Arbeit als paste one.txt two.txtund Entfernen diffs zusätzliche Zeichen , die angezeigt werden mit sedtrivial ist mit dem Schreiben zu vergleichen / eine Erinnerung awkSkript. Auch mit beiden als Funktionen .bash_rclänger! = Besser, lesbarer, schneller .. was ist hier der Vorteil?
Chris Seymour

2

Wenn Sie die dynamische Feldlängenzählung aus Barmars Antwort entfernen, wird der Befehl viel kürzer. Sie benötigen jedoch noch mindestens ein Skript, um die Arbeit abzuschließen, die unabhängig von der gewählten Methode nicht vermieden werden konnte.

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

2

Wenn Sie den tatsächlichen Unterschied zwischen zwei Dateien nebeneinander ermitteln möchten, verwenden Sie diff -y:

diff -y file1.cf file2.cf

Sie können auch eine Ausgabebreite mit der folgenden -W, --width=NUMOption festlegen :

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

und um diffdie Spaltenausgabe an Ihr aktuelles Terminalfenster anzupassen:

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

2

Es gibt einen sedWeg:

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

Unter könnten Sie verwenden 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 /;"

(Natürlich prist die Lösung von @Hasturkun die genaueste !) :

Vorteil von sedüberpr

Sie können die Trennbreite und / oder Trennzeichen fein wählen:

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 /;"

Oder zum Beispiel, um Linien zu markieren, die Folgendes enthalten 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"

wird rendern:

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

1

Nachfolgend finden Sie eine Python-basierte Lösung.

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]

Beispiel

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
Apfel
Birne
längere Linie als die letzten beiden
letzte Linie
[root /]# cat /two.txt
Der schnelle braune Fuchs..
foo
Bar
Linux
[root@RHEL6-64 /]# diff -y one.txt two.txt
Apfel | Der schnelle braune Fuchs..
Birne | foo
längere Linie als die letzten beiden | Bar
letzte Zeile | Linux

sdiffist das, diff -ywas ich in der Frage diskutiere.
Chris Seymour

Ja, richtig ... es wurde erwähnt, dass eine andere Befehls- / Flag-Einstellung angezeigt wird.
iAdhyan

Die Fragen werden jedoch nicht beantwortet, und es werden diffZeichen zwischen den beiden Dateien hinzugefügt.
Chris Seymour

Ich finde es beängstigend, dass du das als Wurzel
machst
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.