Exibir dois arquivos lado a lado

94

Como dois arquivos de texto não classificados de comprimentos diferentes podem ser exibidos lado a lado (em colunas) em umshell

Dado one.txte 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

Exibição:

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

                                    skipped a line

paste one.txt two.txtquase faz o truque, mas não alinha as colunas muito bem, pois apenas imprime uma guia entre as colunas 1 e 2. Eu sei como fazer isso com emacs e vim, mas quero que a saída seja exibida para stdout para ect de tubulação.

A solução que encontrei usa sdiffe canaliza o sed para remover os acréscimos de saída sdiff.

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

Eu poderia criar uma função e colocá-la no meu, .bashrcmas certamente já existe um comando para isso (ou uma solução mais limpa potencialmente)?

Chris Seymour
fonte
Não em um shell, mas vale a pena mencionar: use meld !
fedorqui 'SO pare de prejudicar'

Respostas:

166

Você pode usar prpara fazer isso, usando o -msinalizador para mesclar os arquivos, um por coluna, e -tpara omitir cabeçalhos, por exemplo.

pr -m -t one.txt two.txt

saídas:

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

                                    skipped a line

Veja também:

Hasturkun
fonte
15
Perfeito! Sabia que algo existiria, nunca ouvi falar prantes. Tentei com 3 arquivos e a saída estava truncada, mas a -wopção resolveu isso. Boa resposta.
Chris Seymour
5
@sudo_o: Fico feliz em ajudar, coreutils está cheio de joias
Hasturkun
1
Existe uma maneira de pr detectar automaticamente a largura da tela?
Matt
2
@Matt: Você pode usar $COLUMNS, que deve ser fornecido pelo shell.
Hasturkun
1
Quando usado para imprimir dois arquivos lado a lado, prcorta o final de linhas longas. Existe uma maneira de quebrar as linhas?
molnarg de
32

Para expandir um pouco a resposta de @Hasturkun : por padrão, prusa apenas 72 colunas para sua saída, mas é relativamente fácil fazê-lo usar todas as colunas disponíveis de sua janela de terminal:

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

A maioria dos shells armazenará (e atualizará) a largura da tela do seu terminal na $COLUMNSvariável de ambiente, portanto, estamos apenas passando esse valor prpara usar na configuração de largura de saída.

Isso também responde à pergunta de @Matt :

Existe uma maneira de pr detectar automaticamente a largura da tela?

Então, não: prele mesmo não consegue detectar a largura da tela, mas estamos ajudando um pouco passando a largura do terminal pela -wopção.

pvandenberk
fonte
7

Se você sabe que os arquivos de entrada não têm guias, usar expandsimplifica a resposta de @oyss :

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

Se houver guias nos arquivos de entrada, você sempre pode expandir primeiro:

paste <(expand one.txt) <(expand two.txt) | expand --tabs=50
Prumo
fonte
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])}
}'

O uso *em uma especificação de formato permite fornecer o comprimento do campo dinamicamente.

Barmar
fonte
1
Nunca disse que sim, mas se eu quero exibir dois arquivos lado a lado ocasionalmente, então fazer diff -y one.txt two.txtum trabalho melhor do que paste one.txt two.txtremover diferentes caracteres extras que são exibidos sedé trivial em comparação com escrever / lembrar um awkscript. Mesmo com ambas as funções em .bash_rcmais tempo! = Melhor, mais legível, mais rápido .. qual é a vantagem aqui?
Chris Seymour
2

remover dinamicamente o comprimento do campo contando da resposta de Barmar tornará o comando muito mais curto ... mas você ainda precisa de pelo menos um script para terminar o trabalho que não poderia ser evitado, não importa o método escolhido.

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

Se você quiser saber a diferença real entre dois arquivos lado a lado, use diff -y:

diff -y file1.cf file2.cf

Você também pode definir uma largura de saída usando a -W, --width=NUMopção:

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

e para fazer diffa saída da coluna de caber na janela do terminal atual:

diff -y -W $COLUMNS file1.cf file2.cf
user3498040
fonte
2

Existe uma sedmaneira:

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

Debaixo , você poderia usar 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 /;"

(Claro que a solução de @Hasturkun pré a mais precisa !) :

Vantagem de sedmaispr

Você pode escolher com precisão a largura de separação e / ou separadores:

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, por exemplo, para marcar linhas contendo 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"

irá renderizar:

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
fonte
1

Encontre abaixo uma solução baseada em 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]

Exemplo

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

                                 skipped a line
funk
fonte
0
diff -y <file1> <file2>


[root /]# cat /one.txt
maçã
pera
linha mais longa que as duas últimas
última linha
[root /]# cat /two.txt
A rápida Raposa marrom..
foo
Barra
linux
[root@RHEL6-64 /]# diff -y one.txt two.txt
maçã | A rápida Raposa marrom..
pêra | foo
linha mais longa do que as duas últimas | Barra
última linha | linux
iAdhyan
fonte
sdiffé o diff -yque discuto na pergunta.
Chris Seymour
Sim, certo ... foi mencionado para mostrar outra configuração de comando / sinalizador de fazer isso.
iAdhyan
Mas não responde às perguntas diffadiciona caracteres entre os dois arquivos.
Chris Seymour
Acho assustador você estar fazendo isso como root ...
Pryftan