tags:

views:

78

answers:

5

Is it possible to add spaces to the left of every output to stdout (and stderr if possible) when I run commands in a bash shell script?

I'd like to do something like:

#!/bin/bash
echo Installing: Something
echo "    => installing prerequisite1"

## INSERT MAGICAL LEFT SPACES COMMAND HERE ##

apt-get install -q -y prerequisite

## ANOTHER MAGICAL CANCELLING LEFT SPACES COMMAND HERE ##

echo "    => installing prerequisite2"
# ... the padding again ...
wget http://abc.com/lostzilla.tar.gz
tar vzxf lostzilla.tar.gz
cd lostzilla-1.01
./configure
make && make install
# ... end of padding ...

echo Done.

Any idea?

EDIT: Added quotes to the echo command, otherwise they won't be padded.

+3  A: 

Yes, you can quote them for simple things:

echo '    => installing prerequisite1'

and pipe the output through sed for complex things:

tar vzxf lostzilla.tar.gz 2>&1 | sed 's/^/   /'

The 2>&1 puts stdout and stderr onto the stdout stream and the sed replaces every start-of-line marker with three spaces.

How well this will work on something like wget which does all sorts of cursor manipulations I'm not sure.

Example shown here:

pax> ls -1 p*
phase1.py
phase1.sh
phase2.py
phase2.sh
primes.c
primes.exe
primes.sh
primes.stat

pax> ls -1 p* | sed 's/^/   /'
   phase1.py
   phase1.sh
   phase2.py
   phase2.sh
   primes.c
   primes.exe
   primes.sh
   primes.stat

One trick I've used in the past is to ensure that the scripts themselves take care of the indentation:

#!/bin/bash
if [[ "${DONT_EVER_SET_THIS_VAR}" = "" ]] ; then
        export DONT_EVER_SET_THIS_VAR=except_for_here
        $0 | sed 's/^/   /'
        exit
fi
ls -1 p*

This will re-run the script with indentation through sed if it's not already doing so. That way, you don't have to worry about changing all your output statements. A bit of a hack, I know, but I tend to just do what's necessary for quick-and-dirty shell scripts.

paxdiablo
I can use wget -q for omitting output. But I guess your idea is very cool. I'll try it. Thanks!
kolrie
From `wget(1)`, about the progress bar: "If the output is not a TTY, the "dot" bar will be used by default." I gave it a shot and it worked well. Thanks for the neat trick.
sarnold
+1  A: 

Depending on how the command writes to stdout, you can just indent with a simple awk script:

$ echo -e 'hello\nworld' | awk '{print "    ",$0}'
     hello
     world
Mark Rushakoff
+3  A: 

If you want to turn spacing on and off, use the following awk script:

#!/usr/bin/gawk -f

/^#SPACEON/ { spaces=1; }
/^#SPACEOFF/ { spaces=0; }
!/^#SPACE/ { 
    if(spaces) {
        print "    " $0;
    } else {
        print $0;
    }
}

Note that there are slight problems with your bash scipt. Notably, the use of => in your echo statements will output the character = to the file "installing".

#!/bin/bash

echo Installing: Something
echo '=> installing prerequisite1'

echo '#SPACEON'

echo You would see apt-get install -q -y prerequisite

echo '#SPACEOFF'
echo '=> installing prerequisite2'
echo '#SPACEON'


echo You would see wget http://abc.com/lostzilla.tar.gz
echo You would see tar vzxf lostzilla.tar.gz
echo You would see cd lostzilla-1.01
echo You would see ./configure
echo You would see make \&\& make install

echo '#SPACEOFF'
echo Done.

Combining the two gives me:

$ ./do-stuff | ./magic-spacing 
Installing: Something
=> installing prerequisite1
    You would see apt-get install -q -y prerequisite
=> installing prerequisite2
    You would see wget http://abc.com/lostzilla.tar.gz
    You would see tar vzxf lostzilla.tar.gz
    You would see cd lostzilla-1.01
    You would see ./configure
    You would see make && make install
Done.

Where do-stuff is your bash script and magic-spacing is my awk script above.

bstpierre
Would it be possible to embed the awk snippet into the bash script by doing something like /usr/bin/gawk -F <<EOF ... EOF? I will try it!
kolrie
@kolrie - You could, but you'd need to redirect stdout into that embedded awk snippet. Perhaps by putting the main body into a function and then redirecting output of the function into the snippet?
bstpierre
A: 

Quite un-magical you can use printf to do the following:

# space padding for single string
printf "%-4s%s\n" "" "=> installing prerequisite1"

# space padding for single command output
# use of subshell leaves original IFS intact
( IFS=$'\n'; printf "    %s\n" $(command ls -ld * 2>&1) )

# note: output to stderr is unbuffered
( IFS=$'\n'; printf "    %s\n" $(command ls -ld * 1>&2) )

It's also possible to group commands by enclosing them in curly braces and space-padd their output like so:

{
cmd1 1>&2
cmd2 1>&2
cmd3 1>&2
} 2>&1 | sed 's/.*/    &/'
yabt
A: 

It's possible to redirect stdout to stderr script/shell-wide using exec ...

( 
exec 1>&2
command ls -ld * 
) 2>&1 | sed 's/^/    /'
tom