Is there a way to check which line number of a bash
script is being executed "right now"?
Using bash -x script.sh
looks promising; however, I need to get the current line number.
Is there a way to check which line number of a bash
script is being executed "right now"?
Using bash -x script.sh
looks promising; however, I need to get the current line number.
Yes, there is a way.
There is an array of line numbers where a function has been called.
Define this function:
f(){ echo "${BASH_LINENO[-2]}"; }
And call f
at any line that you want the line number, for example:
#!/bin/bash
f(){ echo "${BASH_LINENO[-2]}"; }
f
echo next1
f
echo next2
f
echo next 3
f
Will print:
6
next 1
9
next 2
12
next 3
15
It could be expanded to show the trail of functions called:
#!/bin/bash
f(){
for ((i=${#BASH_LINENO[@]}-1;i>=0;i--)); do
printf '<%s:%s> ' "${FUNCNAME[i]}" "${BASH_LINENO[i]}";
done
echo "$LINENO"
}
SomeOtherFunction(){ echo -n "test the line numbering: "; f; }
f
echo next 1
echo -n " This line numbering: "; f
SomeOtherFunction
echo next 2
echo -n " This line numbering: "; f
SomeOtherFunction
echo next 3
echo -n " This line numbering: "; f
Which will print:
$ ./script
<main:0> <f:12> 7
next 1
This line numbering: <main:0> <f:15> 7
test the line numbering: <main:0> <SomeOtherFunction:16> <f:10> 7
next 2
This line numbering: <main:0> <f:19> 7
test the line numbering: <main:0> <SomeOtherFunction:20> <f:10> 7
next 3
This line numbering: <main:0> <f:23> 7
Note that above the echo "$LINENO"
output is always the same (7 in this case).
Here’s a solution
that borrows parts of l0b0’s and DopeGhoti’s answers
(and, to a lesser extent, sorontar’s).
Like those answers, mine uses $LINENO
to discover the line number;
unlike them, I use trap
to trigger the reporting.
bash’s trap
command is described in bash(1):
trap [-lp] [[arg] sigspec ...]
The command arg is to be read and executed when the shell receives signal(s) sigspec. … ︙
… If a sigspec is DEBUG, the command arg is executed before every simple command,for
command,case
command,select
command, every arithmeticfor
command, and before the first command executes in a shell function …
So this script:
$ cat -n myscript
1 #!/bin/bash
2 trap 'printf "%3d: " "$LINENO"' DEBUG
3 date
4 sleep 30
5 date
6 sleep \
7 11
8 date
9
10 ls -l
11 for f in *
12 do
13 echo "$f" &&
14 ls -ld "$f"
15 done
16
17 for ((i=0; i<3; i++))
18 do
19 echo "i = $i"; date
20 done
21
22 echo $((5+25+12))
$
runs the printf "%3d: " "$LINENO"
command
before every command in the script, and produces this output:
$ ./myscript 3: Wed, Apr 05, 2017 10:16:17 AM 4: 5: Wed, Apr 05, 2017 10:16:47 AM 7: 8: Wed, Apr 05, 2017 10:16:58 AM 10: total 4 -rwxr-xr-x 1 myusername mygroup 221 Apr 5 10:01 myscript -rwxr-xr-x 1 myusername mygroup 252 Apr 5 10:01 myscript2 -rw-r--r-- 1 myusername mygroup 132 Apr 5 09:59 myscript2.log -rw-r--r-- 1 myusername mygroup 45 Apr 5 08:34 other_file 11: 13: myscript 14: -rwxr-xr-x 1 myusername mygroup 221 Apr 5 10:01 myscript 11: 13: myscript2 14: -rwxr-xr-x 1 myusername mygroup 252 Apr 5 10:01 myscript2 11: 13: myscript2.log 14: -rw-r--r-- 1 myusername mygroup 132 Apr 5 09:59 myscript2.log 11: 13: other_file 14: -rw-r--r-- 1 myusername mygroup 45 Apr 5 08:34 other_file 17: 17: 19: i = 0 19: Wed, Apr 05, 2017 10:16:59 AM 17: 17: 19: i = 1 19: Wed, Apr 05, 2017 10:16:59 AM 17: 17: 19: i = 2 19: Wed, Apr 05, 2017 10:16:59 AM 17: 17: 22: 42 $
Notes:
sleep
, which spans script lines 6 and 7,
is reported as line 7.for f in *
) is reported once
before each iteration of that for
loop.echo "$f"
and ls -ld "$f"
are correctly reported
on their respective lines (13 and 14).for ((i=0; i<3; i++))
) is reported twice
before each iteration of that for
loop,
and twice more after the last iteration.set -x
, LINENO
and PS4
(which are specified by the POSIX standard),
the DEBUG trap
is a bash extension and will not work in all shells.trap
can run any command(s),
and is not restricted to writing to the script’s standard output
or standard error.The question says, «check which line number of a bash script is being executed “right now”» without specifying a user interface. Another approach is to continually write the current line number to a log file:
$ diff myscript myscript2 2c2 < trap 'printf "%3d: " "$LINENO"' DEBUG --- > exec 6> myscript2.log && trap 'printf "%3d\n" "$LINENO" >&6' DEBUG $ ./myscript2 Wed, Apr 05, 2017 10:23:50 AM Wed, Apr 05, 2017 10:24:20 AM Wed, Apr 05, 2017 10:24:31 AM total 4 -rwxr-xr-x 1 myusername mygroup 221 Apr 5 10:01 myscript -rwxr-xr-x 1 myusername mygroup 252 Apr 5 10:01 myscript2 -rw-r--r-- 1 myusername mygroup 24 Apr 5 10:23 myscript2.log -rw-r--r-- 1 myusername mygroup 45 Apr 5 08:34 other_file myscript -rwxr-xr-x 1 myusername mygroup 221 Apr 5 10:01 myscript myscript2 -rwxr-xr-x 1 myusername mygroup 252 Apr 5 10:01 myscript2 myscript2.log -rw-r--r-- 1 myusername mygroup 60 Apr 5 10:23 myscript2.log other_file -rw-r--r-- 1 myusername mygroup 45 Apr 5 08:34 other_file i = 0 Wed, Apr 05, 2017 10:24:31 AM i = 1 Wed, Apr 05, 2017 10:24:31 AM i = 2 Wed, Apr 05, 2017 10:24:31 AM 42 $
We can monitor the execution of this script
by monitoring the contents of the myscript2.log
file
from another terminal.
For example, during the second sleep
,
$ tail myscript2.log
3
4
5
7
You can echo $LINENO
in a script and it should output whatever line that command happens to be on.
#!/bin/bash
echo $LINENO
$ ./foo.sh
2
#!/bin/bash -x
Add that "-x" at the start of your script. Then every time you execute the script it will echo the line your script is executing. like an execution tree of your script.