438

I have a shell script with the following line in it:

[ "$DEBUG" == 'true' ] && set -x
Ulrich Eckhardt
  • 16,572
  • 3
  • 28
  • 55
Ole
  • 41,793
  • 59
  • 191
  • 359
  • 26
    Take a look: `help -m set | less` – Cyrus Mar 29 '16 at 01:05
  • 6
    Thanks for the `help -m set` tip. That works. I tried `man set` prior to asking, however on ubuntu there is `No manual entry for set ` – Ole Mar 29 '16 at 05:18
  • 3
    @Ole, `set` is built into bash so if you `man bash` you can find it in the SHELL BUILTIN COMMANDS section. When viewing the man page you can probably jump to it by searching for this regexp: `\bset \[`. – User5910 Sep 28 '18 at 17:10
  • 8
    `man` is for non-builtins and `help` is for shell builtins. – codeforester Feb 08 '21 at 06:06
  • 1
    BTW, the string comparison operator should be `=` not `==`; the latter is a nonstandard extension, the former is [officially standardized](https://pubs.opengroup.org/onlinepubs/9699919799/utilities/test.html) and guaranteed to be available in all POSIX-compliant `sh` implementations. – Charles Duffy Jun 26 '23 at 19:37

3 Answers3

623

set -x enables a mode of the shell where all executed commands are printed to the terminal. In your case it's clearly used for debugging, which is a typical use case for set -x: printing every command as it is executed may help you to visualize the control flow of the script if it is not functioning as expected.

set +x disables it.

Sled
  • 18,541
  • 27
  • 119
  • 168
John Zwinck
  • 239,568
  • 38
  • 324
  • 436
  • 5
    This is VERY useful! I wish someone had told me that earlier. Are there other interesting tricks like this that can sort of boost up our meta-skill on scripting? – Student Jun 27 '19 at 13:22
  • 23
    @Student: `set -e` at the top of your script will make the script exit with an error whenever an error occurs (and is not explicitly handled). I find that immensely preferable to the default, which is to keep going willy-nilly (like Visual Basic's infamous `On Error Resume Next`). – John Zwinck Jun 28 '19 at 06:41
  • 5
    @JohnZwinck, unfortunately, `set -e` has *very* undesirable side effects, to the point that it makes code review almost impossible (because a given line's behavior depends on what's up the call stack -- if a function is called in a "checked" context, `set -e` is disabled for that invocation and everything it in turn calls). See the exercises in [BashFAQ #105](http://mywiki.wooledge.org/BashFAQ/105#Exercises). – Charles Duffy Feb 16 '20 at 03:49
  • @CharlesDuffy: In my experience, `set -e` is so useful that I'd mark it as recommended in almost any shell script review. You haven't made it clear which solution you're advocating for (tediously checking every command? checking only some commands? using Python instead?). And your link contains this text: *"rking's personal recommendation is to go ahead and use set -e, but beware of possible gotchas. It has useful semantics, so to exclude it from the toolbox is to give into FUD."* I suspect this is an area open to debate, but my coworkers have always agreed that `set -e` is better than not. – John Zwinck Feb 16 '20 at 08:32
  • 2
    @JohnZwinck, Yes, but I have no idea who `rking` is. Greycat is the author of the BashFAQ, the channel elder of the freenode IRC #bash channel, etc -- if you're going to argue-by-authority, it helps to know who the authorities in a field are. And yes, I absolutely do argue for tediously checking every command's exit handling, just as a code review requires in C or Go, or any other language that doesn't support exceptions. To rely on `set -e` is to rely on something that is simply *not reliable*. – Charles Duffy Feb 16 '20 at 19:23
  • 6
    btw: these messages are printed to stderr, so if you for example have such a script running inside a docker container, these messages are interpreted as errors. :) – rudi Aug 10 '20 at 12:56
  • This answer makes no reference to whether this is a bash only feature or it's part of POSIX. – Chris Stryczynski Dec 16 '22 at 15:35
107

$(set -x)

Prints 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.

[source]

Example

set -x
echo $(expr 10 + 20)
+ expr 10 + 20
+ echo 30
30

set +x
echo $(expr 10 + 20)
30

Above example illustrates the usage of set -x. When it is used, above arithmetic expression has been expanded. We could see how a single line has been evaluated step by step.

  • First step expr has been evaluated.
  • Second step echo has been evaluated.

To know more about set → visit this link

when it comes to your shell script,

[ "$DEBUG" == 'true' ] && set -x

Your script might have been printing some additional lines of information when the execution mode selected as DEBUG. Traditionally people used to enable debug mode when a script called with optional argument such as -d

Raju
  • 2,902
  • 8
  • 34
  • 57
  • 1
    Think about using `$( )` instead of backticks when writing examples -- it's been part of the POSIX.2 standard since its initial publication in the early 1990s so there's no meaningful portability loss, and it's much better form (nests well, doesn't change the meaning of backslashes contained within, &c). – Charles Duffy Jun 26 '23 at 19:39
  • Thanks for suggestion @CharlesDuffy, Agreed with your comment and I have updated the answer ! – Raju Jun 27 '23 at 11:04
23

-u: disabled by default. When activated, an error message is displayed when using an unconfigured variable.

-v: inactive by default. After activation, the original content of the information will be displayed (without variable resolution) before the information is output.

-x: inactive by default. If activated, the command content will be displayed before the command is run (after variable resolution, there is a ++ symbol).

Compare the following differences:

/ # set -v && echo $HOME
/root
/ # set +v && echo $HOME
set +v && echo $HOME
/root

/ # set -x && echo $HOME
+ echo /root
/root
/ # set +x && echo $HOME
+ set +x
/root

/ # set -u && echo $NOSET
/bin/sh: NOSET: parameter not set
/ # set +u && echo $NOSET
Community
  • 1
  • 1
lupguo
  • 1,525
  • 13
  • 13