An overview of the

Usually when learning Daniel’s Shell script, we often see a lot of commands beginning with set at the beginning of the script, such as

#! /usr/bin/env bash
set -e
set -u
set- x orset -eux
Copy the code

However, people often overlook the meaning of these set commands, but I will say that this command is actually very powerful, providing debug efficiency and security for scripts. Let’s take a look at what these commands really mean.

The set command is a built-in shell command. You can run help set to view the help information about the set. Its main function is to change the value of shell options and positional parameters, or to display the name and value of shell variables. In the terminal, if you run the set command, all the environment configuration information under the current shell will be displayed.

Error handling

Normally, after each Linux shell command is executed, an execution result is returned and saved to $? In the command output, 0 indicates that the command is executed successfully. Non-0 indicates that the command fails to be executed. For instance,

$ set
$ echo$? 0 0 meanssetThe command is executed successfully.Copy the code

Shell scripts typically use a large number of commands, and strictly speaking, we should carefully examine the execution results of each key command to determine the subsequent execution logic. The general treatment situation is as follows

#! /usr/bin/env bash
PID=`pidof dockers`
RET=$?
if [ $RET -eq 0 ];then
  echo "docker's pid is $PID"
else
  echo "docker don't run"
fi 
 # Pidof will fail if you write dockers.
Copy the code

If command is less, this method may be acceptable, if the size of the shell script is larger, it is conceivable that if were handled in this way, the entire script code structure will become very ugly, and, if we forget to check return command, could lead to a script execution is disorder, cause system is not safe. An elegant solution to this problem is the -e option, which means that if a command exits in a non-zero state, the entire shell script exits immediately. For instance,

#! /usr/bin/env bash
PID=`pidof dockers`
echo "pidof return 1"If, we don't addset-e, the execution result of the script is pidofreturn 1
Copy the code

When set -e is added, the result of the script execution is:

Insert a code slice hereCopy the code

As you can see, when pidof returns 1, the shell immediately exits and does not continue, ensuring a safe exit of the script. In this case, if set -e is enabled, the script will exit immediately. This is not desirable. There are two ways to do this:

#! /usr/bin/env bash
set-e ... .set +e 
command 1
command 2
set-e ... .Copy the code

Run set +e to disable the -e option, and run set -e to punch in the -e option again.

#! /usr/bin/env bash
set-e ... . command1 ||trueexitCopy the code

-o errexit is equivalent to the -e option.

Variable undefined

In shell scripts, if an undefined variable is encountered, it will be treated as null, for example,

#! /usr/bin/env bash
echo $NONE
echo "NONE not set"
Copy the code

The NONE variable has never been defined. Printing NONE will display null, and the following statement will be printed. This is not safe, and we want the shell to prompt and exit immediately when it encounters an undefined variable. The -u option is a perfect solution to this problem. Add set -u to the script above and execute it again. The result is:

#! /usr/bin/env bash
set -u
echo $NONE
echo "NONE not set"
Copy the code

Here are the results:

$/set.sh: line 18: NONE: unbound variablesCopy the code

As you can see, when the shell detects the undefined variable NONE, it immediately prompts and exits the shell. -o nounset is the same as -U.

debug

When writing a large shell script, it is impossible to write the correct script once. When a bug occurs, we may want to have a look at the execution flow of the script. The -x option can print the currently executed command to facilitate debugging and tracking the execution flow of the script.

#! /usr/bin/env bash
set -x
ls set.sh
echo "ABC"
+ ls set.sh
set.sh
+ echo ABC
ABC
Copy the code

The + sign indicates the current command. -o xtrace is the same as the -x option.

The pipe

Pipe as the ultimate weapon of shell processing, are often used to deal with complex business processing, can be in a pipeline command sequence, as long as the last command execution is successful, the whole pipeline command sequence processing returns 0, which makes us cannot track pipe command execution results among them, the -e option is then is useless, for instance,

#! /usr/bin/env bash
set -e
cmd | echo "abc"
echo "efg"The command output is as follows: abc. /set.sh: Line 23: CMD: efg is not foundCopy the code

As you can see, “efg” is printed even though the CMD command failed. Therefore, for pipe commands, set -e is no longer constrained, and the shell provides the -o pipefail option to check the execution status of pipe commands. If this option is enabled, the shell script will exit as soon as there is a failed command in the pipe.

#! /usr/bin/env bash
set -eo pipefail
cmd | echo "abc"
echo "efg"Run ABC./set.sh: Line 23: CMD: No command is foundCopy the code

conclusion

After the above analysis, I believe you have seen a few common set options and their specific meaning, they are so important that they should be added at the beginning of any script, not only to provide scripting, debugging efficiency and avoid many security pitfalls. The common way of writing is as follows:

#! /usr/bin/env bash
set -eux
set -o pipefail
Copy the code