What is the meaning of the number of + signs in stderr in Bash when "set -x"

Viewed 44

In Bash, you can see

set --help

  -x  Print commands and their arguments as they are executed.

Here's test code:

# make script
echo '
    #!/bin/bash
    set -x
    n=$(echo "a" | wc -c)
    for i in $(seq $n)
    do
        file=test_$i.txt
        eval "ls -l | head -$i"> $file
        rm $file
    done
' > test.sh
# execute
chmod +x test.sh
./test.sh 2> stderr
# check
cat stderr

Output

+++ echo a
+++ wc -c
++ n=2
+++ seq 2
++ for i in $(seq $n)
++ file=test_1.txt
++ eval 'ls -l | head -1'
+++ ls -l
+++ head -1
++ rm test_1.txt
++ for i in $(seq $n)
++ file=test_2.txt
++ eval 'ls -l | head -2'
+++ ls -l
+++ head -2
++ rm test_2.txt

What is the meaning of the number of + signs at the beginning of each row in the file? It's kind of obvious, but I want to avoid misinterpreting.
In addition, can a single + sign appear there? If so, what is the meaning of it?

2 Answers

The number of + represents subshell nesting depth.

Note that the entire test.sh script is being run in a subshell because it doesn't begin with #!/bin/bash. This has to be on the first line of the script, but it's on the second line because you have a newline at the beginning of the echo argument that contains the script.

When a script is run this way, it's executed by the original shell in a subshell, approximately like

( source test.sh )

Change that to

echo '#!/bin/bash
    set -x
    n=$(echo "a" | wc -c)
    for i in $(seq $n)
    do
        file=test_$i.txt
        eval "ls -l | head -$i"> $file
        rm $file
    done
' > test.sh

and the top-level commands being run in the script will have a single +.

So for example the command

n=$(echo "a" | wc -c)

produces the output

++ echo a
++ wc -c
+ n='       2'

echo a and wc -c are executed in the subshell created for the command substitution, so they get two +, while n=<result> is executed in the original shell with a single +.

From man bash:

-x
After expanding each simple command, for command, case command, select command, or arithmetic for command, display the expanded value of PS4, followed by the command and its expanded arguments or associated word list.

So what's PS4 here?

PS4
The value of this parameter is expanded as with PS1 and the value is printed before each command bash displays during an execution trace. The first character of the expanded value of PS4 is replicated multiple times, as necessary, to indicate multiple levels of indirection. The default is + .

The meaning of "indirection" is not further explained, as far as I can find...

Related