Can I display a text file in multiple vertical panes?

2

I've got a text file with lots of 60 character long lines where I do a search with the "/" command to highlight the hits. I would like to visually inspect this long file with the highlighted text but on a multi-pane layout instead of having only text in the first 60 char of my terminal window. For example:

less file.txt
/CG <enter> #to find occurrences of token 'CG'

Instead of having 60-char lines like this:

xxxxxxxxxx
xxxxCGxxxx
xxxxxxxxxx
xxxxxxCGxx
xxxCGxxxxx
[...]

I would like to have something like this (here 4 vertical panes):

xxxxxxCGxx|xxCGxxxxxx|xxCGxxxxxx|xxxxxxxxxx
xxxxxxxxxx|xxxxxxxxxx|xxxxxxxCGx|xxxxCGxxxx
xxxxCGxxxx|xxxxCGxxxx|xxxxxxxxxx|xxxxxxxxxx
xxxxxxxxxx|xxxxxxxxxx|xxxxxCGxxx|xxxCGxxCGx
xxCGxxxxxx|xxxxxxCGxx|xxxxxxxxxx|xxxxxxxxxx
[...]

In this way, every time I hit "Page Down", I would scroll down 4x more text than with one pane.

719016

Posted 2011-08-15T10:57:33.127

Reputation: 2 899

Answers

1

This is simple with a bit of a hack. This is how I did it when I needed something similar in the past (but for doing it properly you need to find out the total lines of your file first and stop capturing lines after the end of lines otherwise you need to ctrl-c to end the loop and you will loose the last line if you don't have $tot_lines % $col_num==0)

perl -lne '$|=1; $c1= $_; $c2=scalar <>; $c3=scalar <>; \
           chomp($c1, $c2, $c3); \
           print join("|", $c1, $c2, $c3); \
           ' \
           long_text_60_chars.txt \
| less

This is the easy answer where the input lines spread line wise.

[note] you need to unbuffer the print if you want to pass it to less (due to the input waiting <> when less lines than wanted <>)

You complicate yourself and want to have lines spread column-wise, but then you need to know the pager lines size and the total number of lines of your file. For a 50 lines pager:

perl -lne 'BEGIN{$|=1; $max = 1301; $cl = 50; $pl = $cl*3; $pleft=$max % $pl; $cleft=$max % $cl; $pmax=$max - $pleft; $cmax=$max - $cleft;   print "cleft $cleft, pleft $pleft, pmax $pmax, cmax $cmax"}; if ($.<=$pmax){ @c1= ($_,map{$x=<>;chomp $x;$x} 2..$cl); @c2=map{$x=<>;chomp $x;$x} 1..$cl; @c3=map{$x=<>;chomp $x;$x} 1..$cl; foreach my $idx (0..($cl-1)){ print join("|", $c1[$idx], $c2[$idx], $c3[$idx]) }; print (q{=} x (3*60).qq{\n});  print "line $., pmax $pmax"; } else { print }'  long_text_60_chars_with_num_line.txt   | less

I have put a lot of debugging info so you can adapt it to your needs.

Here is a version human friendly (but copy paste may not work)

perl -lne 'BEGIN{$|=1; \
          # max num lines (from wc -l) \
          $max=1301; \
          #lines per col \
          $cl=50; \
          # lines per pager \
          $pl=$cl*3; \
          # remainder lines for pager \
          $pleft=$max % $pl;  \
          # remainder lines for col \
          $cleft=$max % $cl;  \
          # max line for last full 3col page \
          $pmax=$max - $pleft;  \
          # max line for last full column \
          $cmax=$max - $cleft;  \
          # print info \
          print "cleft $cleft, pleft $pleft, pmax $pmax, cmax $cmax"};  \
          # END BEGIN \
          # START -n while LOOP \
          if ($.<=$pmax){ \
            # full 3col pages               \
            @c1= ($_,map{$x=<>;chomp $x;$x} 2..$cl); \
            @c2=map{$x=<>;chomp $x;$x} 1..$cl;  \
            @c3=map{$x=<>;chomp $x;$x} 1..$cl;  \
              foreach my $idx (0..($cl-1)){ \
                print join("|", $c1[$idx], $c2[$idx], $c3[$idx]) \
              }; \
            print (q{=} x (3*60).qq{\n}); \
            print "line $., pmax $pmax"; \
            } else { \
              # lazy approach: everyting else one column \
              print \
            }'  \
long_text_60_chars_with_num_line.txt  \
| less

Pablo Marin-Garcia

Posted 2011-08-15T10:57:33.127

Reputation: 247

1

Cut the file into screen sized chunks of lines and paste it back together with a pipe delimiter:

#!/bin/bash

working=/tmp/split.$$
pastetmp=/tmp/pasted.$$
screen_height=25
panes=4

rm -rf "$working" "$pastetmp"

mkdir -p "$working"
cd "$working"
split -l "$screen_height" "$1"

four=()
for file in * ; do
     four=("${four[@]}" "$file")
     if [ ${#four[@]} = "$panes" ] ; then
          paste -d'|' "${four[@]}" >> "$pastetmp"
          four=()
     fi
done

[ ${#four[@]} -gt 0 ] && paste -d'|' "${four[@]}" >> "$pastetmp"

less "$pastetmp"

Call like:

./script file.txt

Note: Not tested, but you get the idea.

phogg

Posted 2011-08-15T10:57:33.127

Reputation: 899