Mostrar dos archivos uno al lado del otro

94

¿Cómo se pueden mostrar dos archivos de texto sin clasificar de diferentes longitudes uno al lado del otro (en columnas) en unshell

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

Monitor:

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

                                    skipped a line

paste one.txt two.txtcasi hace el truco, pero no alinea las columnas bien, ya que solo imprime una pestaña entre la columna 1 y 2. Sé cómo hacerlo con emacs y vim, pero quiero que la salida se muestre en stdout para piping, etc.

La solución que se me ocurrió usa sdiffy luego tuberías a sed para eliminar los sdiffagregados de salida .

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

Podría crear una función y pegarla en mi, .bashrcpero seguramente ya existe un comando para esto (o una solución más limpia ).

Chris Seymour
fuente
No en un caparazón, pero vale la pena mencionarlo: ¡usa meld !
fedorqui 'SO deja de dañar'

Respuestas:

166

Puede usar prpara hacer esto, usando la -mbandera para fusionar los archivos, uno por columna, y -tpara omitir encabezados, por ejemplo.

pr -m -t one.txt two.txt

salidas:

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

                                    skipped a line

Ver también:

Hasturkun
fuente
15
¡Perfecto! Sabía que existiría algo, nunca prantes escuchado . Intenté con 3 archivos y la salida se truncó, pero la -wopción resolvió eso. Buena respuesta.
Chris Seymour
5
@sudo_o: Feliz de ayudar, coreutils está lleno de gemas
Hasturkun
1
¿Hay alguna forma de que pr pueda detectar automáticamente el ancho de la pantalla?
Matt
2
@Matt: Podría usar $COLUMNS, que debería ser proporcionado por el shell.
Hasturkun
1
Cuando se utiliza para imprimir dos archivos uno al lado del otro, prcorta el final de líneas largas. ¿Hay alguna forma de hacer que envuelva las líneas?
molnarg
32

Para expandir un poco la respuesta de @Hasturkun : de forma predeterminada, prusa solo 72 columnas para su salida, pero es relativamente fácil hacer que use todas las columnas disponibles de la ventana de su terminal:

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

La mayoría de los shell almacenarán (y actualizarán) el ancho de pantalla de su terminal en la $COLUMNSvariable de entorno, por lo que solo estamos pasando ese valor prpara usarlo en la configuración del ancho de salida.

Esto también responde a la pregunta de @Matt :

¿Hay alguna forma de que pr pueda detectar automáticamente el ancho de la pantalla?

Entonces, no: por prsí solo no puede detectar el ancho de pantalla, pero estamos ayudando un poco al pasar el ancho del terminal a través de la -wopción.

pvandenberk
fuente
7

Si sabe que los archivos de entrada no tienen pestañas, entonces el uso expandsimplifica la respuesta de @oyss :

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

Si pudiera haber pestañas en los archivos de entrada, siempre puede expandir primero:

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

El uso *de una especificación de formato le permite proporcionar la longitud del campo de forma dinámica.

Barmar
fuente
1
Nunca dije que lo hiciera, pero si quiero mostrar dos archivos uno al lado del otro de vez en cuando, hacer diff -y one.txt two.txtun trabajo mejor que paste one.txt two.txteliminar los caracteres adicionales de diffs que se muestran sedes trivial en comparación con escribir / recordar un awkscript. ¡Incluso con ambas funciones en .bash_rcmás tiempo! = Mejor, más legible, más rápido ... ¿cuál es la ventaja aquí?
Chris Seymour
2

eliminar dinámicamente el recuento de longitud de campo de la respuesta de Barmar lo hará un comando mucho más corto ... pero aún necesita al menos un script para terminar el trabajo que no se pudo evitar sin importar el método que elija.

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

Si desea conocer la diferencia real entre dos archivos uno al lado del otro, use diff -y:

diff -y file1.cf file2.cf

También puede establecer un ancho de salida usando la -W, --width=NUMopción:

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

y para hacer que diffla salida de la columna se ajuste a su ventana de terminal actual:

diff -y -W $COLUMNS file1.cf file2.cf
usuario3498040
fuente
2

Hay una sedforma:

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

Debajo , podrías 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 /;"

(¡Por supuesto que la solución de @Hasturkun pres la más precisa !) :

Ventaja de sedmáspr

Puede elegir con precisión el ancho de separación o los 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 /;"

O, como muestra, para marcar líneas que contengan 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"

rendirá:

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

Encuentre a continuación una solución basada en 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]

Ejemplo

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

                                 skipped a line
canguelo
fuente
0
diff -y <file1> <file2>


[root /]# cat /one.txt
manzana
Pera
línea más larga que las dos últimas
Última línea
[root /]# cat /two.txt
El veloz zorro marrón..
foo
bar
linux
[root@RHEL6-64 /]# diff -y one.txt two.txt
manzana | El veloz zorro marrón..
pera | foo
línea más larga que las dos últimas | bar
última línea | linux
iAdhyan
fuente
sdiffes diff -ylo que discuto en la pregunta.
Chris Seymour
Sí, claro ... se mencionó para mostrar otra configuración de comando / bandera para hacerlo.
iAdhyan
Pero no responde a las preguntas, diffagrega caracteres entre los dos archivos.
Chris Seymour