4

I have bash script where i have echo before every command showing what is happening.

But i need to disbale echo when setting as cron job and then enable again if do some testing.

i find it very hard to go to each line and then add/remove comment

is there anything which i can include at top something like

enable echo or disable echo

so that i don't have to waste time

Mahakaal
  • 2,075
  • 9
  • 27
  • 38

8 Answers8

20

The absolute easiest would be to insert the following line after the hashbang line:

echo() { :; }

When you want to re-enable, either delete the line or comment it out:

#echo() { :; }

If you're not using echo but printf, same strategy, i.e.:

printf() { :; }

If you absolutely need to actually echo/printf something, prepend the builtin statement, e.g.:

builtin echo "This 'echo' will not be suppressed."

This means that you can do a conditional output, e.g.:

echo () {
  [[ "$SOME_KIND_OF_FLAG" ]] && builtin echo $@
}

Set the SOME_KIND_OF_FLAG variable to something non-null, and the overridden echo function will behave like normal echo.


EDIT: another alternative would be to use echo for instrumenting (debugging), and printf for the outputs (e.g., for piping purposes). That way, no need for any FLAG. Just disable/enable the echo() { :; } line according to whether you want to instrument or not, respectively.


Enable/Disable via CLI Parameter

Put these lines right after the hashbang line:

if [[ debug == "$1" ]]; then
  INSTRUMENTING=yes  # any non-null will do
  shift
fi
echo () {
  [[ "$INSTRUMENTING" ]] && builtin echo $@
}

Now, invoking the script like this: script.sh debug will turn on instrumenting. And because there's the shift command, you can still feed parameters. E.g.:

  • Without instrumenting: script.sh param1 param2
  • With instrumenting: script.sh debug param1 param2

The above can be simplified to:

if [[ debug != "$1" ]]; then
  echo () { :; }
  shift
fi

if you need the instrumenting flag (e.g. to record the output of a command to a temp file only if debugging), use an else-block:

if [[ debug != "$1" ]]; then
  echo () { :; }
  shift
else
    INSTRUMENTING=yes
fi

REMEMBER: in non-debug mode, all echo commands are disabled; you have to either use builtin echo or printf. I recommend the latter.

pepoluan
  • 6,132
  • 4
  • 46
  • 76
  • i tried that but gave some error , i had the statement like `echo "Backing up ...."$FOLDER/$DATE` . did that line has any problem – Mahakaal May 12 '11 at 05:49
  • @Mahakaal I just tested, and I got no error. But then again, you should put `$FOLDER/$DATE` *inside* the quotes, i.e. : `"Backing up ... $FOLDER/$DATE"` – pepoluan May 12 '11 at 06:17
  • i tried adding that line at below hashbang , and then i tested without any echo statement , i still get error it says `Unexpected end of file` – Mahakaal May 12 '11 at 07:18
  • @Mahakaal ... omigosh, I just realized: It should be `:;` instead of just `:`. I've been testing the 'conditional output' one. I'll fix my answer. Sorry for the oversight. – pepoluan May 12 '11 at 07:29
  • wow that worked perfectly , that was the answer i was looking for , all others were sort of hacks but this was prefect. also is it possible that i can pass something on commandline and then it displays echo othwise not like `/bin/sh abc.sh yes` and then it displays echos – Mahakaal May 12 '11 at 08:08
  • @Mahakaal sorry, just saw your question. Yes, use the version with the 'FLAG'. Test $1 for your signal, and if $1 matches your signal, set the FLAG variable to something not null. – pepoluan May 12 '11 at 20:18
  • @Mahakaal I've further edited my answer to show you how it's done. – pepoluan May 13 '11 at 02:27
12

Several things:

Don't use echo at all

Instead use set -xv to set debug mode which will echo each and every command. You can set PS4 to the desired prompt: for example PS4='$LINENO: ' will print out the line number on each line. In BASH, I believe it's the same. Then, you don't have to clean up your script. To shut off, use set +xv.

Example:

foo=7
bar=7
PS4='$LINENO: '
set -xv   #Begin debugging
if [ $foo = $bar ]
then
    echo "foo certainly does equal bar"
fi

set +xv   #Debugging is off

if [ $bar = $foo ]
then
    echo "And bar also equals foo"
fi

Results:

$ myprog.sh
if [ $foo = $bar ]
then
    echo "foo certainly does equal bar"
fi

5: [ 7 = 7 ]
7: echo 'foo certainly does equal bar'
foo certainly does equal bar
set +xv   #Debugging is off

And bar also equals foo

Use a function

Define a function instead of using echo:

Example:

function myecho {
    if [ ! -z "$DEBUG" ]
    then
        echo "$*"
    fi
}
DEBUG="TRUE"
my echo "Will print out this line"
unset DEBUG
myecho "But won't print out this line"

Use the nop command

The colon (:) is the nop command in BASH. It doesn't do anything. Use an environment variable and define it as either echo or :. When set to a colon, nothing happens. When set to echo, the line prints.

Example:

echo=":"
$echo "This line won't print"
echo="echo"
$echo "But this line will."
Roy Rico
  • 3,683
  • 6
  • 35
  • 36
David W.
  • 105,218
  • 39
  • 216
  • 337
2

Not sure if I miss the below solution to use a variable (e.g. debug) at the start of the bash script.

Once you set the debug=true, any conditional-if will enable or disable multiple “echo statements” in bash script.

 typeset debug=false # set to true if need to debug
...
 if [ $debug == "true" ]; then
     echo
     echo "Filter"
     read
 fi
...
 if [ $debug == "true" ]; then
     echo
     echo "to run awk"
 fi
Nasri Najib
  • 1,261
  • 11
  • 6
2

Building on Matthew's answer, how about something like this:

myEcho = "/bin/true"
if [ ! "$CRON" ]: then
    myEcho = "/bin/echo"
fi

and then use $myEcho instead of echo in your script?

QuantumMechanic
  • 13,795
  • 4
  • 45
  • 66
  • Alternatively, you could probably use an alias, then it isn't even a variable (and you could alias echo itself). – Chris Shaffer May 12 '11 at 02:01
  • 1
    That's not valid bash syntax. You need to have no spaces around the `=` signs (if you do, it will be interpreted as executing the command `myEcho` with `=` as its first argument), and use a semicolon or newline instead of the colon between the `if` and `then`. – Brian Campbell May 12 '11 at 02:33
1

You can do one better. If you setup your crontab as detailed in another answer, you can then check if you are running in cron and only print if you are not. This way you don't need to modify your script at all between different runs.

You should then be able to use something like this (probably doesn't quite work, I'm not proficient in bash):

if [ ! "$CRON" ]; then
  echo "Blah blah"
fi
Community
  • 1
  • 1
Matthew Scharley
  • 127,823
  • 52
  • 194
  • 222
  • True, but if he has lots of echo statements that could be kinda annoying to wrap them all in a guard `if` like that. – QuantumMechanic May 12 '11 at 01:52
  • @QuantumMechanic: It's a once off job, then it's done. Beats changing your script every time you are running it, since he's already commenting every single echo anyway. – Matthew Scharley May 12 '11 at 01:53
1

Try set -v at the top to echo each command. To stop echoing change it to set +v.

fedorqui
  • 275,237
  • 103
  • 548
  • 598
grok12
  • 3,526
  • 6
  • 26
  • 27
1

Couldn't post a code block in a comment, so I'll post this as an answer.

If you're a perfectionist (like I am) and don't want the last set +x line to be printed... and instead print Success or FAIL, this works:

(
  set -e # Stop at first error
  set -x # Print commands
  set -v # Print shell input lines as they are read

  git pull

  // ...other commands...

) && echo Success || echo FAIL

It will create a sub process, though, which may be an overkill solution.

tink
  • 14,342
  • 4
  • 46
  • 50
thejhh
  • 181
  • 1
  • 5
0

If you're running it in cron, why not just dump the output? Change your crontab entry so that it has > /dev/null at the end of the command, and all output will be ignored.

Daenyth
  • 35,856
  • 13
  • 85
  • 124