1

I need a function to show, only during debug, a message (the function name):

#!/bin/bash

debug_function(){ if [[ $DEBUG -eq 1 ]]; then echo "${FUNCNAME[1]}" else DEBUG=0 fi }

test_function(){ debug_function echo "something" }

foo=$(test_function)

echo "Result: $foo"

It works, but in DEBUG=1 the function name is added to function output obviously.

# sh test
Result: something

DEBUG=1 sh test

Result: test_function something

Is there a way to print only a message?

Using wall I get the right behavior, but are there some other alternatives?

Thank you

  • 1
    Note when you run sh test the shebang is totally irrelevant (see this). Pure sh cannot run your code. Your sh apparently can, but this is "accidental". The code is for bash and the shebang looks right. Make the file executable and run it as ./test. – Kamil Maciorowski Apr 16 '21 at 10:26
  • Totally right, just for test I din't set +x on script. – Marco Cicala Apr 17 '21 at 14:34

1 Answers1

1

Your echo "${FUNCNAME[1]}" prints to stdout, so its output belongs to the output of the debug_function, which in turn belongs to the output of the test_function.

Print the message to stderr:

  • by redirecting the output of echo:

    echo "${FUNCNAME[1]}" >&2
    
  • or by redirecting the entire output of debug_function (if the whole function should print only to stderr) when you call debug_function:

    debug_function >&2
    

The latter method allows commands inside the debug_function to print straightforwardly to stdout. What they print will be redirected because stdout of the debug_function is redirected.

The function itself can redirect its stdout to its stderr with exec >&2. This will affect all commands in the function. But this will also affect the calling function/script, unless the redirecting function is run in a subshell.

You can run the function in a subshell on demand with (debug_function). To always run the function in a subshell, use () instead of {} when defining the function.

So a function whose entire purpose is to print to stderr and not to stdout can be defined like:

debug_function()(
   exec >&2
   echo whatever
   # ...
)

Now echo and other commands in the function don't need >&2. Even if you call the function simply as debug_function, the commands in it will print to stderr.

Note: stdout or stderr of one subshell or command can be different than stdout or stderr of another subshell or command or the script as a whole. Redirections are possible on many levels. Therefore even a function that does exec >&2 in its own subshell can ultimately write to stdout of the whole script, if "proper" redirections happen outside of the function body. I won't elaborate.

The most important thing to remember:

Stdout is often captured (like in your case) or piped further. The main point of stderr is not to let error/debug/diagnostic messages pollute stdout.