Visualizza due file fianco a fianco


94

Come possono essere visualizzati fianco a fianco (in colonne) 2 file di testo non ordinati di diversa lunghezza in un fileshell

Dato 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

Schermo:

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

                                    skipped a line

paste one.txt two.txtfa quasi il trucco ma non allinea bene le colonne in quanto stampa solo una scheda tra la colonna 1 e 2. So come farlo con emacs e vim ma voglio che l'output venga visualizzato su stdout per piping ect.

La soluzione che mi è venuta in mente usa sdiffe poi pipe a sed per rimuovere l'output sdiffaggiunge.

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

Potrei creare una funzione e inserirla nel mio .bashrcma sicuramente un comando per questo esiste già (o potenzialmente una soluzione più pulita )?


Non in un guscio, ma vale la pena menzionarlo: usa la fusione !
fedorqui 'SO smettila di nuocere'

Risposte:


166

Puoi usare prper farlo, usando il -mflag per unire i file, uno per colonna, e -tper omettere le intestazioni, ad es.

pr -m -t one.txt two.txt

uscite:

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

                                    skipped a line

Guarda anche:


15
Perfetto! Sapevo che sarebbe esistito qualcosa, mai sentito prprima. Ho provato con 3 file e l'output è stato troncato ma l' -wopzione ha risolto il problema. Bella risposta.
Chris Seymour

5
@sudo_o: Felice di aiutare, coreutils è pieno di gemme
Hasturkun

1
Esiste un modo per consentire a pr di rilevare automaticamente la larghezza dello schermo?
Matt

2
@ Matt: potresti usare $COLUMNS, che dovrebbe essere fornito dalla shell.
Hasturkun

1
Quando viene utilizzato per stampare due file affiancati, prtaglia la fine delle righe lunghe. C'è un modo per avvolgere le linee?
molnarg

32

Per espandere un po 'la risposta di @Hasturkun : per impostazione predefinita prutilizza solo 72 colonne per il suo output, ma è relativamente facile fargli usare tutte le colonne disponibili della finestra del terminale:

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

La maggior parte delle shell memorizzerà (e aggiornerà) la larghezza dello schermo del tuo terminale nella $COLUMNSvariabile di ambiente, quindi stiamo solo passando quel valore a prda utilizzare per l'impostazione della larghezza dell'output.

Questo risponde anche alla domanda di @Matt :

Esiste un modo per consentire a pr di rilevare automaticamente la larghezza dello schermo?

Quindi no: di per prsé non può rilevare la larghezza dello schermo, ma stiamo aiutando un po 'passando la larghezza del terminale tramite l' -wopzione.


7

Se sai che i file di input non hanno schede, l'utilizzo expandsemplifica la risposta di @oyss :

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

Se ci potrebbero essere delle schede nei file di input, puoi sempre espandere prima:

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

L'utilizzo *in una specifica di formato consente di fornire dinamicamente la lunghezza del campo.


1
Non l'ho mai detto, ma se voglio visualizzare due file fianco a fianco di tanto in tanto, fare diff -y one.txt two.txtun lavoro migliore di paste one.txt two.txte rimuovere i caratteri aggiuntivi diff che vengono visualizzati con sedè banale rispetto alla scrittura / memorizzazione di uno awkscript. Anche con entrambe le funzioni in .bash_rcpiù! = Migliore, più leggibile, più veloce .. qual è il vantaggio qui?
Chris Seymour

2

rimuovere dinamicamente il conteggio della lunghezza del campo dalla risposta di Barmar lo renderà un comando molto più breve ... ma è comunque necessario almeno uno script per completare il lavoro che non può essere evitato indipendentemente dal metodo scelto.

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

2

Se vuoi conoscere l'effettiva differenza tra due file fianco a fianco, usa diff -y:

diff -y file1.cf file2.cf

È inoltre possibile impostare una larghezza di output utilizzando l' -W, --width=NUMopzione:

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

e per fare in modo diffche l'output della colonna di si adatti alla finestra del terminale corrente:

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

2

C'è un sedmodo:

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

Sotto , potresti usare 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 /;"

(Ovviamente la soluzione di @Hasturkun prè la più accurata !) :

Vantaggio di sedpiùpr

È possibile scegliere con precisione la larghezza di separazione e / oi separatori:

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

Oppure, per esempio, per contrassegnare le righe contenenti 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"

renderà:

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

1

Trova di seguito una soluzione basata su 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]

Esempio

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
Mela
Pera
linea più lunga delle ultime due
ultima linea
[root /]# cat /two.txt
La rapida volpe marrone ..
foo
bar
linux
[root@RHEL6-64 /]# diff -y one.txt two.txt
mela | La rapida volpe marrone ..
pera | foo
linea più lunga delle ultime due | bar
ultima riga | linux

sdiffè quello diff -yche discuto nella domanda.
Chris Seymour

Sì, giusto ... è stato menzionato per mostrare un'altra impostazione di comando / flag per farlo.
iAdhyan

Ma non risponde alle domande diffaggiunge caratteri tra i due file.
Chris Seymour

Trovo spaventoso che tu lo stia facendo come root ...
Pryftan
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.