125

If I enter bash -x option, it will show all the line. But the script will execute normally.

How can I execute line by line? Than I can see if it do the correct thing, or I abort and fix the bug. The same effect is put a read in every line.

user2672165
  • 2,986
  • 19
  • 27
Rodrigo
  • 11,909
  • 23
  • 68
  • 101
  • 2
    Perhaps more broadly see also https://stackoverflow.com/questions/951336/how-to-debug-a-bash-script/45096876#45096876 – tripleee Oct 02 '17 at 04:54

5 Answers5

162

You don't need to put a read in everyline, just add a trap like the following into your bash script, it has the effect you want, eg.

#!/usr/bin/env bash
set -x
trap read debug

< YOUR CODE HERE >

Works, just tested it with bash v4.2.8 and v3.2.25.


IMPROVED VERSION

If your script is reading content from files, the above listed will not work. A workaround could look like the following example.

#!/usr/bin/env bash
echo "Press CTRL+C to proceed."
trap "pkill -f 'sleep 1h'" INT
trap "set +x ; sleep 1h ; set -x" DEBUG

< YOUR CODE HERE >

To stop the script you would have to kill it from another shell in this case.


ALTERNATIVE1

If you simply want to wait a few seconds before proceeding to the next command in your script the following example could work for you.

#!/usr/bin/env bash
trap "set +x; sleep 5; set -x" DEBUG

< YOUR CODE HERE >

I'm adding set +x and set -x within the trap command to make the output more readable.

organic-mashup
  • 1,980
  • 2
  • 12
  • 9
30

The BASH Debugger Project is "a source-code debugger for bash that follows the gdb command syntax."

Rob Bednark
  • 25,981
  • 23
  • 80
  • 125
  • 4
    This is really the best solution. It allows viewing the line before it is run (and much more). On most systems it can be installed with `apt-get install bashdb`. Then you just need to run `bashdb your_command.sh`, type `step`, and then hit carriage return after that. – studgeek Jan 16 '17 at 19:35
  • 1
    @studgeek it is not available on Redhat/CentOS etc. so I would not call that "most systems". – Sajuuk Feb 07 '18 at 08:30
  • @Sajuuk, it may not be *packaged*, but it's absolutely *available*. – Charles Duffy Apr 14 '18 at 21:20
  • macOS: `brew install bashdb` – boweeb Oct 09 '19 at 19:22
  • 1
    @CharlesDuffy: it's not in the default Ubuntu repos either. – Dan Dascalescu Mar 02 '20 at 17:58
  • `sudo apt-get install bashdb` not works on Ubuntu 20.04 I download tarball file from https://sourceforge.net/projects/bashdb/ Install bashdb from source. It's instruction is here. https://www.howtogeek.com/105413/how-to-compile-and-install-from-source-on-ubuntu/ And using bashdb is here. https://www.howtogeek.com/105413/how-to-compile-and-install-from-source-on-ubuntu/ – Bench Vue Feb 13 '22 at 15:05
  • When I build bashdb for RHEL UBI 8 (using the 4.4 branch, since that's the version of bash there), it shows 40 errors. So I'm not sure it's good for every situation... – AdamC Mar 07 '22 at 19:42
  • It's available on Ubuntu 20.04, but it installs version 4.3. There seems to be a bug with this because I get an immediate error upon executing the debugger. Like the previous comments, I had to build and install from source which does work. – rayryeng Jul 12 '22 at 05:34
3

Have a look at bash-stepping-xtrace.

It allows stepping xtrace.

mug896
  • 1,777
  • 1
  • 19
  • 17
3

If your bash script is really a bunch of one off commands that you want to run one by one, you could do something like this, which runs each command one by one when you increment a variable LN, corresponding to the line number you want to run. This allows you to just run the last command again super easy, and then you just increment the variable to go to the next command.

Assuming your commands are in a file "it.sh", run the following, one by one.

$ cat it.sh
echo "hi there"
date
ls -la /etc/passwd

$ $(LN=1 && cat it.sh | head -n$LN | tail -n1)
"hi there"

$ $(LN=2 && cat it.sh | head -n$LN | tail -n1)
Wed Feb 28 10:58:52 AST 2018

$ $(LN=3 && cat it.sh | head -n$LN | tail -n1)
-rw-r--r-- 1 root wheel 6774 Oct 2 21:29 /etc/passwd
Brad Parks
  • 66,836
  • 64
  • 257
  • 336
  • This does not work for multi-line commands – see Apr 25 '21 at 08:19
  • yeah for sure - I do mention that in the description though - so if you have `if` statements that aren't on one line, or while loops, etc, it wont work for that! – Brad Parks Apr 25 '21 at 11:14
1

xargs: can filter lines

cat .bashrc | xargs -0 -l -d \\n bash
  • -0 Treat as raw input (no escaping)
  • -l Separate each line (Not by default for performances)
  • -d \\n The line separator
Tinmarino
  • 3,693
  • 24
  • 33