bashawksedstdoutinteractive

Indent long line stdout


Let's say I have a standard 80 columns terminal, execute command with long line output (i.e. stdout from ls) that splits into two or more lines, and want to indent the continuation line of all my bash stdout.

Indent should be configurable, 1 or 2 or 3 or whatever spaces.

from this

lrwxrwxrwx 1 root root 24 Feb 19 1970 sdcard -> /storage/emula
ted/legacy/

to this

lrwxrwxrwx 1 root root 24 Feb 19 1970 sdcard -> /storage/emula
ted/legacy/

Read this Indenting multi-line output in a shell script so I tried to pipe | sed 's/^/ /' but gives me the exact opposite, indents the first lines and not the continuation.

Ideally I would put a script in profile.rc or whatever so every time I open an interactive shell and execute any command long output gets indented .


Solution

  • I'd use for this.

    awk -v width="$COLUMNS" -v spaces=4 '
    BEGIN {
      pad = sprintf("%*s", spaces, "") # generate `spaces` spaces
    }
    NF {                               # if current line is not empty
      while (length > width) {         # while length of current line is greater than `width`
        print substr($0, 1, width)     # print `width` chars from the beginning of it
        $0 = pad substr($0, width + 1) # and leave `pad` + remaining chars
      }
      if ($0 != "")                    # if there are remaining chars
        print                          # print them too 
      next
    } 1' file
    

    In one line:

    awk -v w="$COLUMNS" -v s=4 'BEGIN{p=sprintf("%*s",s,"")} NF{while(length>w){print substr($0,1,w);$0=p substr($0,w+1)} if($0!="") print;next} 1'
    

    As @Mark suggested in comments, you can put this in a function and add it to .bashrc for ease of use.

    function wrap() {
      awk -v w="$COLUMNS" -v s=4 'BEGIN{p=sprintf("%*s",s,"")} NF{while(length>w){print substr($0,1,w);$0=p substr($0,w+1)} if($0!="") print;next} 1'
    }
    

    Usage:

    ls -l | wrap
    

    Edit by Ed Morton per request:

    Very similar to oguzismails script above but should work with Busybox or any other awk:

    $ cat tst.awk
    BEGIN { pad = sprintf("%" spaces "s","") }
    {
        while ( length($0) > width ) {
            printf "%s", substr($0,1,width)
            $0 = substr($0,width+1)
            if ( $0 != "" ) {
                print ""
                $0 = pad $0
            }
        }
        print
    }
    $
    $ echo '123456789012345678901234567890' | awk -v spaces=3 -v width=30 -f tst.awk
    123456789012345678901234567890
    $ echo '123456789012345678901234567890' | awk -v spaces=3 -v width=15 -f tst.awk
    123456789012345
       678901234567
       890
    $ echo '' | awk -v spaces=3 -v width=15 -f tst.awk
    
    $
    

    That first test case is to show that you don't get a blank line printed after a full-width input line and the third is to show that it doesn't delete blank rows. Normally I'd have used sprintf("%*s",spaces,"") to create the pad string but I see in a comment that that doesn't work in the apparently non-POSIX awk you're using.