Wyświetl dwa pliki obok siebie

95

W jaki sposób 2 nieposortowane pliki tekstowe o różnej długości mogą być wyświetlane obok siebie (w kolumnach) w plikushell

Podano one.txti 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

Pokaz:

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

                                    skipped a line

paste one.txt two.txtprawie załatwia sprawę, ale nie wyrównuje ładnie kolumn, ponieważ po prostu wypisuje jedną tabulację między kolumnami 1 i 2. Wiem, jak to zrobić z emacsem i vimem, ale chcę, aby wyjście było wyświetlane na standardowe wyjście dla potoku itp.

Rozwiązanie, które wymyśliłem, używa, sdiffa następnie rur do seda, aby usunąć wyjście, sdiffdodaje.

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

Mógłbym stworzyć funkcję i umieścić ją w moim, .bashrcale na pewno polecenie do tego już istnieje (lub potencjalnie czystsze rozwiązanie)?

Chris Seymour
źródło
Nie w skorupce, ale warto wspomnieć: użyj meld !
fedorqui 'SO przestać krzywdzić'

Odpowiedzi:

167

Możesz prto zrobić, używając -mflagi do łączenia plików, po jednym na kolumnę, i -tpomijania nagłówków, np.

pr -m -t one.txt two.txt

wyjścia:

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

                                    skipped a line

Zobacz też:

Hasturkun
źródło
15
Idealny! Wiedziałem, że coś będzie istnieć, o czym nigdy wcześniej nie słyszano pr. Próbowałem z 3 plikami i dane wyjściowe zostały obcięte, ale -wopcja rozwiązała ten problem. Niezła odpowiedź.
Chris Seymour,
5
@sudo_o: Chętnie pomożemy, coreutils jest pełen klejnotów
Hasturkun
1
Czy istnieje sposób, aby pr automatycznie wykrył szerokość ekranu?
Matt,
2
@Matt: Możesz użyć tego $COLUMNS, co powinno być dostarczone przez powłokę.
Hasturkun
1
Kiedy jest używany do drukowania dwóch plików obok siebie, prodcina końce długich linii. Czy istnieje sposób, aby zawijał linie?
molnarg
32

Aby nieco rozwinąć odpowiedź @Hasturkun : domyślnie prużywa tylko 72 kolumn do wyjścia, ale stosunkowo łatwo jest sprawić, by używał wszystkich dostępnych kolumn w oknie terminala:

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

Większość powłok będzie przechowywać (i aktualizować) szerokość ekranu twojego terminala w $COLUMNSzmiennej środowiskowej, więc po prostu przekazujemy tę wartość do prustawienia szerokości wyjścia.

To również odpowiada na pytanie @Matta :

Czy istnieje sposób, aby pr automatycznie wykrył szerokość ekranu?

Więc nie: prsam nie może wykryć szerokości ekranu, ale pomagamy trochę, przekazując szerokość terminala za pomocą -wopcji.

pvandenberk
źródło
7

Jeśli znasz pliki wejściowe nie mają kart, a następnie przy użyciu expandupraszcza @oyss „s odpowiedź :

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

Jeśli w plikach wejściowych mogą znajdować się zakładki, zawsze możesz najpierw rozwinąć:

paste <(expand one.txt) <(expand two.txt) | expand --tabs=50
Pion
źródło
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])}
}'

Użycie *w specyfikacji formatu umożliwia dynamiczne podawanie długości pola.

Barmar
źródło
1
Nigdy nie powiedziałem, że tak, ale jeśli chcę od czasu do czasu wyświetlać dwa pliki obok siebie, to diff -y one.txt two.txtdziała lepiej niż paste one.txt two.txtusuwanie dodatkowych znaków różnicowych, które są wyświetlane, sedjest trywialne w porównaniu z pisaniem / zapamiętywaniem awkskryptu. Nawet z obydwoma funkcjami na .bash_rcdłużej! = Lepiej, bardziej czytelnie, szybciej… jaka jest tutaj zaleta?
Chris Seymour,
2

usuń dynamicznie zliczanie długości pól z odpowiedzi Barmara sprawi, że polecenie będzie znacznie krótsze ... ale nadal potrzebujesz co najmniej jednego skryptu, aby zakończyć pracę, której nie można było uniknąć bez względu na wybraną metodę.

paste one.txt two.txt |awk -F'\t' '{printf("%-50s %s\n",$1,$2)}'
oyss
źródło
2

Jeśli chcesz poznać rzeczywistą różnicę między dwoma plikami obok siebie, użyj diff -y:

diff -y file1.cf file2.cf

Możesz również ustawić szerokość wyjściową za pomocą -W, --width=NUMopcji:

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

i aby diffdopasować kolumny wyjściowe do bieżącego okna terminala:

diff -y -W $COLUMNS file1.cf file2.cf
user3498040
źródło
2

Jest sedsposób:

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

Pod możesz użyć 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 /;"

(Oczywiście rozwiązanie @Hasturkun prjest najdokładniejsze !) :

Zaleta sedponadpr

Możesz precyzyjnie wybrać szerokość separacji i / lub separatory:

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

Lub, na przykład, zaznacz linie zawierające 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"

wyrenderuje:

apple                         |  | The quick brown fox..
pear                          |  | foo
longer line than the last two |ln| bar 
last line                     |ln| linux
                              |  | 
                              |ln| skipped a line
F. Hauri
źródło
1

Znajdź poniżej rozwiązanie oparte na Pythonie.

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]

Przykład

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

                                 skipped a line
boj
źródło
0
diff -y <file1> <file2>


[root /]# cat /one.txt
jabłko
Gruszka
dłuższa linia niż dwie ostatnie
Ostatnia linia
[root /]# cat /two.txt
Szybki brązowy lis..
bla
bar
linux
[root@RHEL6-64 /]# diff -y one.txt two.txt
jabłko | Szybki brązowy lis..
gruszka | bla
dłuższa linia niż ostatnie dwie | bar
ostatnia linia | linux
iAdhyan
źródło
sdiffJest diff -yktóre omówię w pytaniu.
Chris Seymour,
Tak, dobrze ... wspomniano, aby pokazać inne ustawienie polecenia / flagi, które to robi.
iAdhyan,
Ale nie odpowiada na pytania, diffdodaje znaki między dwoma plikami.
Chris Seymour,