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)?


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:


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.


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

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.


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

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

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

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

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

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
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.