Take the 2-minute tour ×
Super User is a question and answer site for computer enthusiasts and power users. It's 100% free, no registration required.

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.

share|improve this question

2 Answers 2

up vote 1 down vote accepted

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
share|improve this answer

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.

share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.