Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Script debugging

Yash-rs offers several features to help debug scripts.

Exiting on errors

Many utilities return a non-zero exit status when they fail, but by default the shell continues executing the next command, which can lead to unexpected results. To stop the script when a command fails, enable the errexit option. For details, see Exiting on errors.

Catching errors across pipeline components

By default, the exit status of a pipeline reflects only the last command, ignoring failures in earlier commands. To make the pipeline fail if any command fails, enable the pipefail shell option. With pipefail, the pipeline’s exit status is that of the last command that returned a non-zero status, or zero if all returned zero. This helps catch errors in pipelines.

The `pipefail` option is not yet implemented in yash-rs.

Blocking unset parameters

Unset parameters expand to an empty string by default, which can silently hide misspelled parameter names, potentially leading to unexpected results if the intended value is unused. To catch such errors early, enable the nounset shell option. With nounset, the shell raises an error whenever an unset parameter is expanded. See Unset parameters for more information.

This option also detects unset variables in arithmetic expressions.

Reviewing command input

When the verbose shell option is enabled, the shell prints each command to standard error as it reads it, before executing. This is useful for reviewing commands being executed, especially in scripts.

$ set -o verbose
$ echo "Hello, world!"
echo "Hello, world!"
Hello, world!
$ set -o verbose
$ greet() {
greet() {
> echo "Hello, world!"
echo "Hello, world!"
> }
}
$ greet
greet
Hello, world!

Tracing command execution

If you enable the xtrace shell option, the shell prints expanded fields in each command to standard error before executing it. This is useful for reviewing actual commands being executed.

$ mkdir $$ && cd $$
$ set -o xtrace
$ for user in Alice Bob Charlie; do
>     echo "Hello, $user!" >> greetings.txt
> done
+ for user in Alice Bob Charlie
+ echo 'Hello, Alice!' 1>>greetings.txt
+ echo 'Hello, Bob!' 1>>greetings.txt
+ echo 'Hello, Charlie!' 1>>greetings.txt
$ cat *.txt
+ cat greetings.txt
Hello, Alice!
Hello, Bob!
Hello, Charlie!

Each line of output is prefixed with the value of the PS4 variable, which defaults to + . Parameter expansion, command substitution, and arithmetic expansion are performed on the PS4 value before printing it.

$ PS4='$((i=i+1))+ '; set -o xtrace
$ while getopts n option -n foo; do
>     case $option in
>         (n) n_option=true ;;
>         (*) echo "Unknown option: $option" ;;
>     esac
> done
1+ getopts n option -n foo
2+ case n in
3+ n_option=true
4+ getopts n option -n foo

Checking syntax

If the exec shell option is unset, the shell only parses commands without executing them. This is useful for checking syntax errors in scripts without running them.

$ set +o exec
$ echo "Hello, world!"
$ echo "Oops, a syntax error";;
error: the compound command delimiter is unmatched
 --> <stdin>:3:28
  |
3 | echo "Oops, a syntax error";;
  |                            ^^ not in a `case` command
  |
# Invoke the shell with the `exec` option unset to check a script file
yash3 +o exec my_script.sh