Display two files side by side

81,039

Solution 1

You can use pr to do this, using the -m flag to merge the files, one per column, and -t to omit headers, eg.

pr -m -t one.txt two.txt

outputs:

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

                                    skipped a line

See Also:

Solution 2

To expand a bit on @Hasturkun's answer: by default pr uses only 72 columns for its output, but it's relatively easy to make it use all available columns of your terminal window:

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

Most shells will store (and update) your terminal's screenwidth in the $COLUMNS shell variable, so we're just passing that value on to pr to use for its output's width setting.

This also answers @Matt's question:

Is there a way for pr to auto-detect screen width?

So, no: pr itself can't detect the screenwidth, but we're helping it out a bit by passing in the terminal's width via its -w option.

Note that $COLUMNS is a shell variable, not an environment variable, so it isn't exported to child processes, and hence the above approach will likely not work in scripts, only in interactive TTYs... see LINES and COLUMNS environmental variables lost in a script for alternative approaches.

Solution 3

If you know the input files have no tabs, then using expand simplifies @oyss's answer:

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

If there could be tabs in the input files, you can always expand first:

paste <(expand one.txt) <(expand two.txt) | expand --tabs=50

Solution 4

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

Using * in a format specification allows you to supply the field length dynamically.

Solution 5

There is a sed way:

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

Under , you could use 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 /;"

(Of course @Hasturkun 's solution pr is the most accurate!):

Advantage of sed over pr

You can finely choose separation width and or separators:

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

Or, for sample, to mark lines containing 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"

will render:

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

Related videos on Youtube

Chris Seymour
Author by

Chris Seymour

Updated on July 08, 2022

Comments

  • Chris Seymour
    Chris Seymour almost 2 years

    How can 2 unsorted text files of different lengths be display side by side (in columns) in a shell

    Given one.txt and 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
    

    Display:

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

    paste one.txt two.txt almost does the trick but doesn't align the columns nicely as it just prints one tab between column 1 and 2. I know how to this with emacs and vim but want the output displayed to stdout for piping ect.

    The solution I came up with uses sdiff and then pipes to sed to remove the output sdiff adds.

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

    I could create a function and stick it in my .bashrc but surely a command for this exists already (or a cleaner solution potentially)?

    • fedorqui
      fedorqui over 7 years
      Not in a shell, but worth mentioning: use meld!
  • Chris Seymour
    Chris Seymour over 11 years
    Perfect! Knew something would exist, never heard of pr before. I tried with 3 files and the output was truncated but the -w option solved that. Nice answer.
  • Hasturkun
    Hasturkun over 11 years
    @sudo_o: Happy to help, coreutils is full of gems
  • Chris Seymour
    Chris Seymour over 10 years
    sdiff is diff -y which I discuss in the question.
  • Vikas Jain
    Vikas Jain over 10 years
    Yes right... it was mentioned to show another command/flag setting of doing it.
  • Chris Seymour
    Chris Seymour over 10 years
    But it doesn't answer the questions diff adds characters between the two files.
  • Matt
    Matt about 10 years
    Is there a way for pr to auto-detect screen width?
  • Hasturkun
    Hasturkun almost 10 years
    @Matt: You could use $COLUMNS, which should be provided by the shell.
  • molnarg
    molnarg about 9 years
    When used to print two files side by side, pr cuts the end of long lines. Is there a way to make it wrap the lines?
  • crw
    crw almost 7 years
    @molnarg: One method is to first fold each input file to half the page width, less any column-separator width. EG, in bash: pr -t -m -w $PAGE_WIDTH <(fold -w $HALF_PAGE_WIDTH one.txt) <(fold -w $HALF_PAGE_WIDTH two.txt). This could be solved elegantly in user-created script.
  • Ashutosh Baheti
    Ashutosh Baheti over 6 years
    Is there a way to show 1 line from first file and 10 lines from the second file? Its machine translation outputs that I want to view side by side.
  • Lichtgestalt
    Lichtgestalt almost 4 years
    pr -mtJ ... to use all available width.
  • alper
    alper over 3 years
    can I apply this for output of two processes instead of a file?
  • Jishnu P Das
    Jishnu P Das about 3 years
    bash 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" Nice solution!! really helpful in other contexts
  • Graham Toal
    Graham Toal about 2 years
    Thanks for the hints here. I've used it in a bash script: pr -m -t -w$((2 * $(cat $1 $2|wc -L))) $1 $2