"Go" shell Script Debug (Bash trap support BASHDB)

Source: Internet
Author: User
Tags control characters set set

Original URL: http://zhu8337797.blog.163.com/blog/static/170617549201122512712136/

Command Options function
BASH–X Pin Name Echo Echo Displays each row of the script after the variable is replaced and before the command is executed
BASH–V Pin Name With Print the lines in the script as you entered before executing
Bash–n Pin Name Do not execute Explain but not execute the command
Set–x Turn on Echo Track execution of scripts
Set +x Turn off Echo Turn off trace feature


Output debug information in a shell script
By adding debug statements to the program, it is the most common debugging means to display information about key areas or where errors occur.
Shell programmers often use the echo (Ksh programmer often uses print) statements to output information, but relying solely on the output trace of the Echo statement is cumbersome, and the large number of ECHO statements that are added to the script during the debug phase will have to be removed one by one of the time when the product is delivered. To solve this problem, this section mainly introduces some methods of how to easily and effectively output debugging information.

1. Using the trap command

The trap command is used to capture the specified signal and execute a pre-defined command.
Its basic syntax is:
Trap ' command ' signal
Where signal is the signal to be captured, the command is the one to execute after capturing the specified signal. You can use the Kill–l command to see all the available signal names in the system, and the command executed after capturing the signal can be any one or more valid shell statements, or a function name.
When the shell script executes, it produces three so-called "pseudo-signals", which are called "pseudo-signals" because the three signals are generated by the shell and other signals are generated by the operating system, and it is helpful to debug by capturing the three "pseudo-signals" using the trap command and outputting the relevant information.

Table 1. Shell Pseudo-Signal
When the signal name is generated
Exit exits from a function or complete script execution
ERR when a command returns a non-0 state (on behalf of the command execution is unsuccessful)
Before each command in the DEBUG script executes

By capturing the exit signal, we can output some of the values of the variables we want to track when the shell script aborts execution or exits from the function, thus judging the execution state of the script and the cause of the error, using the following methods:
Trap ' command ' EXIT or trap ' command ' 0

By capturing the err signal, we can easily trace the execution of unsuccessful commands or functions, and output relevant debugging information, here is a sample program to capture the Err signal, where $lineno is a shell built-in variable that represents the current line number of the shell script.

$ cat-n exp1.sh
1 Errtrap ()
2 {
3 echo "[line:$1] Error:command or function exited with status $?"
5 foo ()
6 {
7 return 1;
9trap ' errtrap $LINENO ' ERR
Here is an example program that tracks variables by capturing the debug signal: (Full tracking of variables)

$ cat–n exp2.sh
1 #!/bin/bash
2 trap ' echo ' before execute line: $LINENO, a= $a, b= $b, c= $c "' DEBUG
3 a=1
4 If ["$a"-eq 1]
5 Then
6 b=2
7 Else
8 B=1
9 fi
Ten c=3
echo "End"

2. Using the tee command

Pipelines and input and output redirects are used very much in shell scripts, and the execution of some commands is directly the input of the next command under the action of the pipeline. If we find that the execution result of a batch of commands connected by a pipeline is not as expected, it is necessary to step through the execution of each command to determine where the problem is, but because the pipeline is used, these intermediate results are not displayed on the screen and are difficult to debug, so we can use the Tee command now.

The tee command reads the data from the standard input, outputs its contents to a standard output device, and saves the content as a file. For example, the following script fragment, which is to get the IP address of the machine:

Ipaddr= '/sbin/ifconfig | grep ' inet addr: ' | Grep-v ' '
| Cut-d:-f3 | awk ' {print '} '
The whole sentence after the #注意 = sign is enclosed in anti-quotation marks (the key to the left of the number 1 key).
Echo $ipaddr
Execute the script again, and then view the contents of the Temp.txt file:

We can see that the second column of the intermediate result (separated by the: number) contains the IP address, and the third column is intercepted using the cut command in the script above, so we just need to change the cut-d:-f3 in the script to cut-d:-f2 can get the correct result.

specifically to the script example above, we may not need the help of the tee command, for example, we can segment the various commands connected by the pipeline and view the output of each command to diagnose the error.

But in some complex shell scripts, the commands that are connected by pipelines may also depend on some of the other variables defined in the script, which makes it much more cumbersome to run each command at the prompt, and it's easier to simply insert a tee command between the pipes to see the intermediate results.

3. Use the "Debug hooks"

In the C language program, we often use debug macros to control whether or not to output debug information, and in shell scripts we can also use such a mechanism, as shown in the following code:

If ["$DEBUG" = "true"]; Then
echo "Debugging" #此处可以输出调试信息

[Email protected]
Debug hooks for Shell versions.

DEBUG () {["$DEBUG" = 0] && {echo "${bash_lineno}:[email protected] _"; [Email protected]; }; }

By defining a debug function, you can make the process of inserting a debug hook more concise and convenient, as shown in the following code:

$ cat–n exp3.sh
1 DEBUG ()
2 {
3 If ["$DEBUG" = "true"]; Then
4 [Email protected]
5 fi
7 a=1
8 DEBUG echo "A= $a"
9 If ["$a"-eq 1]
Ten Then
+ fi
DEBUG echo "b= $b"
DEBUG echo "c= $c"

4. Using the shell's execution options

The debugging method described in the previous section is to locate the error by modifying the source code of the shell script so that it outputs relevant debugging information, does it have a way to debug the shell script without modifying the source code? The answer is to use the shell's execution options, and this section describes the usage of some common options:

-N reads only the shell script, but does not actually execute
-X enters the tracking mode, showing each command executed
-C "string" reads commands from strings

"-n" can be used to test for a syntax error in a shell script, but does not actually execute the command. After shell scripting is complete, it is a good practice to first use the "-n" option to test the script for syntax errors before it is actually executed.

Because some shell scripts will have an impact on the system environment, such as generating or moving files, or if the syntax errors are found in actual execution, you will have to do some manual recovery of the system environment to continue testing the script.

The "-C" option causes the shell interpreter to read and execute shell commands from a string rather than from a file. You can use this option when you need to temporarily test the execution results of a small piece of script, as follows:
Sh-c ' A=1;b=2;let c= $a + $b; echo "C= $c"

The "-X" option can be used to track script execution and is a powerful tool for debugging shell scripts. The "-X" option causes the shell to display each command line that it actually executes during the execution of the script, and displays a "+" sign at the beginning of the row.

The "+" sign is followed by the contents of the command line after the variable substitution, helping to analyze what commands were actually executed. The "-X" option is simple and easy to handle for most shell debugging tasks, and should be used as a preferred debugging tool.

If you combine the trap ' command ' debug mechanism described earlier in this article with the "-X" option, we can output both the actual execution of each command and the value of the relevant variable line by row, which is useful for debugging.

Continue with the exp2.sh described earlier, and now add the "-X" option to execute it:

$ sh–x exp2.sh
+ Trap ' echo ' before execute line: $LINENO, a= $a, b= $b, c= $c "' DEBUG
+ + echo ' before execute line:3, a=,b=,c= '
Before execute Line:3, a=,b=,c=
+ a=1
+ + echo ' before execute line:4, a=1,b=,c= '
Before execute Line:4, a=1,b=,c=
+ ' [' 1-eq 1 '] '
+ + echo ' before execute line:6, a=1,b=,c= '
Before execute Line:6, a=1,b=,c=
+ b=2
+ + echo ' before execute line:10, a=1,b=2,c= '
Before execute line:10, a=1,b=2,c=
+ c=3
+ + echo ' before execute line:11, a=1,b=2,c=3 '
Before execute line:11, a=1,b=2,c=3
+ Echo End

In the above result, the line preceded by the "+" is the command that the shell script actually executes, and the line preceded by the "+ +" sign executes the command specified in the trap mechanism, while the other rows are output information.

The shell's execution options can be specified in the script, in addition to being specified when the shell is started. Set-parameter means that an option is enabled, and set + parameter means that an option is turned off. Sometimes we don't need to use the "-X" option at startup to keep track of all the command lines, so we can work with the set command in our script, as shown in the following script fragment:

The set command can also be invoked using the debug hook-debug function described in the previous section, which avoids the hassle of deleting these debug statements when script delivery is used, as shown in the following script fragment:

DEBUG set-x #启动 "-X" option
Program segments to track
DEBUG set +x #关闭 "-X" option

5. Enhancements to the "-X" option

The "-X" execution option is currently the most commonly used method of tracking and debugging shell scripts, but the output of debugging information is limited to the actual execution of each command after the variable substitution and a "+" prompt at the beginning of the line, even if there is no important information such as row numbers,

For complex shell script debugging, it is still very inconvenient. Fortunately, we can use some of the shell's built-in environment variables to enhance the output information of the "-X" option, which introduces several shell-built environment variables:

Represents the current line number of the shell script, similar to the built-in macro in C __line__

The name of the function, similar to the built-in macro __func__ in C, but the macro __func__ can only represent the current function name, and $funcname is more powerful, it is an array variable containing all the functions on the entire call chain name, so the variable ${funcname[0 ]} represents the name of the function that the shell script is currently executing, and the variable ${funcname[1]} represents the name of the function that called the function ${funcname[0]}, and so on.

$PS 4
The main prompt variable $PS1 and the second-level prompt variable $ps2 are more common, but few people notice the effect of the fourth-level prompt variable $PS4. We know that using the "-X" execution option will show each command that was actually executed in the shell script, and that the value of $PS4 will be displayed in front of each command output by the "-X" option. In the bash shell, the default value of $PS4 is the "+" sign. (Now that you know why the "-X" option is used, the output command has a "+" sign in front of it?) )。

Using the $PS4 feature, we can enhance the output information of the "-X" option by redefining the value of the $PS4 using some built-in variables. For example, execute the export ps4= ' +{$LINENO: ${funcname[0]} ' and then execute the script using the '-X ' option to display its line number and the name of the function it belongs to in front of each actually executed command.

The following is an example of a bug-based shell script that this article will use to demonstrate how to debug a shell script with "-N" and enhanced "-X" execution options. A function isroot () is defined in this script to determine if the current user is a root user, and if not, abort the execution of the script

$ cat–n exp4.sh
1 #!/bin/bash
2 IsRoot ()
3 {
4 If ["$UID"-ne 0]
5 return 1
6 Else
7 return 0
8 fi
Ten IsRoot
One if ["$?"-ne 0]
echo "must is root to run this script"
Exit 1
All else
echo "Welcome root user"
#do something

For example, we can try to customize the value of the $PS4 and use the "-X" option to track:

$ export ps4= ' +{$LINENO: ${funcname[0]} '
$ sh–x exp4.sh
+{10:} isRoot
+{4:isroot} ' [' 503-ne 0 '] '
+{5:isroot} return 1
+{11:} ' [1 '-ne 0 '] '
Exp4.sh:line: [1:command not found
+{16:} echo ' Welcome root user '
Welcome Root User

There are other built-in variables that are useful for debugging, such as Bash_source in the BASH shell, Bash_subshell, and so on, which are useful for debugging built-in variables that you can view with man sh or man BASH. These built-in variables are then used to customize the $PS4 for your debugging purposes, thus achieving the purpose of enhancing the output information of the "-X" option.

Five. Summary

Now let's summarize the process of debugging a shell script:
First use the "-N" option to check for syntax errors, and then use the "-X" option to track the execution of the script.

Before using the "-X" option, don't forget to customize the value of the PS4 variable to enhance the output information of the "-X" option, at least to make it output line number information

(Execute export ps4= ' +[$LINENO] ', and once and for all, add this statement to the. bash_profile file in your home directory.

This will make your commissioning trip easier. You can also use traps, debug hooks and other means to output key debugging information, quickly reduce the scope of troubleshooting errors, and in the script using "Set-x" and "set +x" to focus on some blocks of code tracking.

This way, I believe you can easily catch the bug in your shell script.

If your script is complex enough and requires more debugging, you can use the Shell debugger bashdb, a gdb-like debugging tool that can accomplish many of the features of a shell script, such as breakpoint setting, stepping, variable observation, etc.

Using BASHDB can also be useful for reading and understanding complex shell scripts. The installation and use of BASHDB is outside the scope of this article, you can refer to the documentation on http://bashdb.sourceforge.net/and download the trial.

Six. Some techniques for reading and writing scripts.

Vim + ctags reading script.

Ctags Default Action

Ctags-r generates a tag file for a directory.

Ctags-f the generated tag file name.

For example Ctags-f test_tags./test.sh

Ctags-f test1_tags-r./test1/

Add the tag tag file to Vim.
Vim: Set Tags+=/tmp/test_tags,/tmp/test1_tags
VIM: Set path + =/dev/shm/,/tmp/test1/*
And then you can use it in vim.
Jump to a topic: Place the cursor over a label (for example, |bars|) and enter Ctrl].
Jump back: type Ctrl-t or Ctrl-o

Seven. Pre-defined variables
$ #位置参数的数量 $* The contents of all positional parameters $? The status returned after the command executes is typically 0
$$ the current process number $! the last process number in the background the currently executing process name
A positional parameter is a variable that is determined in the command line of the calling Shell program at its own location, which is the parameter entered after the program name. The positional parameters are separated by a space, the shell takes the first positional parameter to replace $ $ in the program file, the second replaces the $, and so on. $ A is a special variable whose content is the file name of the current shell program, which is the script name.
Variables for parameter substitution
Variable =${parameter-word}: If a parameter is set, the value of the variable is substituted with the value of the parameter, otherwise word is substituted.
Variable =${parameter =word}: If a parameter is set, the value of the variable is substituted with the value of the argument, otherwise the variable is set to Word and then replaced with Word.
Variable =${parameter? Word}: If a parameter is set, the value of the variable is substituted with the value of the parameter, otherwise word is displayed and exited from the shell, and if Word is omitted, the standard information is displayed.
Variable =${parameter +word}: If a parameter is set, the variable is replaced with Word, otherwise it is not displaced.

Local variables
abc= "ABC"
Echo ${ABC}

Clear variable unset variable_name
Show all shell variables set set-a indicates that all variables are exported directly
Set read-only variable readonly variable_name
View all environment Variables env

Eight. Embedding shell variables
Cdpath CD into the Cdpath specified path
Exinit Save using the VI initialization option exinit= ' Set Nu tab=4 '; Export Exinit
IFS is used as the default domain delimiter specified by the shell export ifs=:
PS1 basic prompt with Shell prompt
PS2 Secondary Prompt default >
Term Save terminal type

Nine. Common shell naming:
TTY report connected device or terminal-S ACK script standard input 0 Terminal 1 non-terminal
Uname option-a Show All information-s system name-V only show OS version or release date
Wait process_id waits for process ID processes or all processes to end

Bashname to detach a file name from the path
Cat option File Text file displays command-v display control characters
Touch option file creates a timestamp for the files at the current time-tmmddhhmm
Head-num file Displays the first n rows
Tail-num file Displays the following n rows
More Options File split screen display content-C do not scroll screen-D at pagination display prompt-N per screen display
NL option File column line number-I line number increases every time n
String file to view the text contained in a binary file
Number of characters, number of words, and number of lines-c characters in the WC-option file statistic-L lines-W number of words
Du-sh file/dir Display Size-a displays the size of each file-s displays totals only
Fuser option file-k kills all processes that access the file-u/m show all processes that access the file system

LDD a.out shows the dynamic link library required for the executable file
Readelf the dynamic link library on which the program that identifies the target system depends
File A.out Displays the format of the files

Compress option files to compress the files. Z-v Show Compression results
Uncompass files unzip the file without input. Z
Diff option File1 file1 show two files in inconsistent rows-C output by standard format-I ignores case

LogName Display Login Name
Script option file uses the script command to record the current session-A to append the output to the end of the file
Shutdown now/-g60-i6-y shuts down and restarts after 60 seconds
Sleep Number system waits for a specified count of banknotes

Whereis cmd system command path
Who options-a-r-s

Uname--help-a (all infomation)-S (kernel-name)-N (network hostname)-R (Kernel-release)-V (kernel-version)-M (machine)- P (processor)-I (Hardware-platform)-O (Operationg-system)

"Go" shell Script Debug (Bash trap support BASHDB)

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.