2

Script

#!/bin/bash
set -v
echo "verbose echo"
{ set +v; } &>/dev/null
echo "non verbose echo"

gives the following output:

echo "verbose echo"
verbose echo
{ set +v; } &>/dev/null
non verbose echo

I want to suppress output for { set +v; } &>/dev/null and get the following output:

echo "verbose echo"
verbose echo
non verbose echo

I tried the approach above which is described here for suppressing output for disabling xtrace (x) flag with command { set +x; } &>/dev/null and it is working for this xtrace flag. Have not found related info in manuals for bash and set.

As work around this can be achieved by means of subshell call like shown here. But is this possible without using subshell?

3
  • 3
    With set -v active, each line of the script is outputted when the shell reads it. It has nothing to do with executing the lines. The -x and -v shell options are very different in this regard. You are asking for a way of getting the shell to not output the line that contains the set +v command, when it reads that line. AFAIK, that is impossible as the line has not yet been executed.
    – Kusalananda
    Commented Jul 26 at 7:58
  • @Kusalananda Ah, I see. I noticed that comments are also outputted. There is no option to exclude them when verbose is enabled? Commented Jul 26 at 8:21
  • 2
    @AntonSamokat See the description of v in set(1p) (quoted in my answer below). The wording it uses is "input", which includes comments. Commented Jul 26 at 8:23

1 Answer 1

2

The POSIX description of set(1p) states:

-v The shell shall write its input to standard error as it is read.

Since the command to redirect stdout/stderr of the next command constitutes "input" to the shell, I'm afraid it is not possible to reset the v option without at least outputting the command which redirects stderr itself (or using set -v in a subshell), ie:

echo "verbose echo"
exec 2>/dev/null
set +v
echo "non verbose echo"

gives:

$ bash -v setv.bash
echo "verbose echo"
verbose echo
exec 2>/dev/null
non verbose echo
$

While fulfilling the requirements that subshells are not used and the set(1p) invocation itself is not output, this kind of redirection comes with a downside that subsequent output to stderr will also be redirected to /dev/null unless redirected again, to stdin or such.


The x option to set(1p) is a special case. It is worth noting, that the POSIX states the following:

-x The shell shall write to standard error a trace for each command after it expands the command and before it executes it. It is unspecified whether the command that turns tracing off is traced.

while the GNU Bash Manual states:

-x Print a trace of simple commands, for commands, case commands, select commands, and arithmetic for commands and their arguments or associated word lists after they are expanded and before they are executed. The value of the PS4 variable is expanded and the resultant value is printed before the command and its expanded arguments.

As an aside, with a replacement of &> by 2>, dash (a shell whose design goal is strict POSIX compliance) follows this behavior of Bash and suppresses the output of { set +x; } 2>/dev/null, while for example mksh doesn't:

$ cat setx.sh
echo "verbose echo"
{ set +x; } 2>/dev/null
echo "non verbose echo" >&2
$ dash -x setx.sh
+ echo verbose echo
verbose echo
non verbose echo
$ mksh -x setx.sh
+ echo 'verbose echo'
verbose echo
+ 2>/dev/null
+ set +x
non verbose echo

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .