The technical skills here were originally from Google's "testing on the Toilet" (Tott). Here is a revised and amplified version. Script Security
All of my bash scripts start with the following lines:
#!/bin/bash
set-o nounset
set-o errexit
Doing so avoids two common problems: referring to an undefined variable (the default is "") the command that failed is ignored
It should be noted that some of the parameters of some Linux commands can be enforced to ignore errors such as "Mkdir-p" and "rm-f".
Also note that in the "Errexit" mode, although it is effective to catch errors, but not all failed to capture the command, in some cases, some failed commands are not detected. (For more details, please refer to this post.) ) script Function
In bash you can define functions that, like any other command, can be used arbitrarily; they make your script more readable:
Extractbashcomments () {
egrep "^#"
}
Cat myscript.sh | extractbashcomments | WC
comments=$ (extractbashcomments < myscript.sh)
There are also some examples:
Sumlines () { # iterating over stdin-similar to awk ' local
sum=0 local
line= ' while
read line;
m=$ (${sum} + ${line}) done
echo ${sum}
}
sumlines < data_one_number_per_line.txt
log () { # Classic Logger local
prefix= "[$ (date +%y/%m/%d\%h:%m:%s)]:"
echo "${prefix} $@" >&2
}< C15/>log "INFO" "a Message"
Move your bash code as far as possible into a function, placing only the global variables, constants, and statements that are called to "main" on the outermost layer. variable Annotation
In bash, you can make limited annotations to variables. The most important two annotations are: local (function internal variable) readonly (read-only variable)
# A useful idiom:default_val can be overwritten
# with a environment variable of the same name
readonly D EFAULT_VAL=${DEFAULT_VAL:-7}
MyFunc () {
# Initialize a local variable with the ' global DEFAULT local
some_ Var=${default_val}
...
}
In this way, you can declare a variable that was not a read-only variable as a read-only variable:
x=5
x=6
readonly x
x=7 # failure
Try to annotate all variables in your bash script with local or readonly. use $ () instead of inverted single quotes (')
Inverted single quotes are hard to read and are similar in some fonts to positive single quotes. $ () can be used inline and avoids the hassle of escape characters.
# both commands below print out:a-b-c-d
echo ' A-' echo b-\ ' echo c-\\\ ' echo d\\\ ' \ ' '
echo ' a-$ (Echo b-$ (E Cho D)) "
Replace with [[]] (double bracket) []
using [[]] avoids problems like the file name extension of an exception, and it can lead to a lot of grammatical improvements, and adds a lot of new features:
operator |
function Description |
|| |
Logical OR (used in double brackets only) |
&& |
Logical AND (used in double brackets only) |
< |
String comparisons (no transfer required in double brackets) |
-lt |
Number comparison |
= |
String equality |
== |
String comparisons are globbing (used in double brackets only, refer to the following) |
=~ |
String comparisons with regular expressions (used in double brackets only, reference below) |
-N |
Non-empty string |
-Z |
Empty string |
-eq |
Numbers equal |
-ne |
Numbers ranged |
Single bracket:
[' ${name} ' \> ' A '-o ${name} \< ' m ']
Double Middle bracket
[["${name}" > "a" && "${name}" < "M" ]]
Regular Expression/globbing
The benefits of using double brackets are best illustrated with the following examples:
t= ' abc123 '
[[' $t ' = = abc*]] # True (globbing comparison)
[[' $t ' = = ' abc* ']] # False (literal comparison)
[[$t] =~ [ABC] +[123]+]] # True (regular expression comparison)
[["$t" =~ "abc*"]] # False (literal comparison)
Note that, starting with Bash version 3.2, regular and globbing expressions cannot be wrapped in quotes. If you have a space in your expression, you can store it in a variable:
R= "a B +"
[["A BBB" =~ $r]] # True
String comparisons by globbing can also be used in a case statement:
Case $t in
abc*) <action>
; Esac
string Manipulation
There are a variety of ways to manipulate strings in bash, many of which are undesirable.
Basic User
f= "Path1/path2/file.ext"
len= "${#f}" # = 20 (string length)
# slice operation: ${<var>:<start>} or ${<var>:< START>:<LENGTH>}
slice1= "${f:6}" # = "Path2/file.ext"
slice2= "${f:6:5}" # = "path2" slice3= "${f"
:-8} "# =" File.ext "(Note:"-"before a space)
pos=6
len=5
slice4=" ${f:${pos}:${len}} "# =" path2 "
Replace operation (using globbing)
f= "Path1/path2/file.ext"
single_subst= "${f/path?/x}" # = X/path2/file.ext "global_subst=" ${f//
path?/x} " # = ' X/x/file.ext '
# string split
readonly dir_sep= '/'
array= (${f//${dir_sep}/})
Second_dir= "${arrray[1]}" # = path2
Remove head or tail (using globbing)
f= "Path1/path2/file.ext"
# Delete string header
extension= "${f#*.}" # = ' ext '
# Remove string headers in greedy match
filename= ' ${f##*/} ' # = ' file.ext '
# Delete string tail
dirname= ' ${f%/*} ' # = "Path1/path2"
# Delete string tail
root= "${f%%/*}" in greedy match # = "Path1"
avoid using temporary files
Some commands require a file name as a parameter, so you cannot use the pipe. This time < () is useful, it can accept a command and convert it into something that can be a filename or something:
# Download and compare two page
diff < (Wget-o-URL1) < (Wget-o-URL2)
Another very useful place is "here documents", which allows you to enter multiple lines of string on the standard input. The following ' MARKER ' can be replaced with any word.
# any word can be used as a delimiter
command << MARKER
... ${var}
$ (cmd) ...
MARKER
If there are no inline variable substitution operations in the text, you can wrap the first marker in single quotes:
Command << ' MARKER ' ...
No substitution is happening here.
$ (dollar sign) is passed through verbatim.
...
MARKER
Built-in variables
variable |
Description |
$ |
Script Name |
$n |
N parameters passed to script/function |
$$ |
The PID of the script |
$! |
PID of the last executed command (process running in background) |
$? |
Exit status of previous command (Pipe command using ${pipestatus}) |
$# |
Number of arguments passed to the script/function |
$@ |
All parameters passed to the script/function (identifying each parameter) |
$* |
All arguments passed to the script/function (take all parameters as a string) |
TipsUsing $* is rarely the right choice. $@ can handle space parameters, and the spaces between the parameters can be handled correctly. Use $@ should be enclosed in double quotes, like "$@".
Debugging
To perform a syntax check on a script:
Bash-n myscript.sh
Trace the execution of each command in the script:
Bash-v myscripts.sh
Trace the execution of each command in the script and append the extension information:
Bash-x myscript.sh
You can use Set-o verbose and set-o xtrace to permanently specify-V and-O in the script header. This is useful when executing a script on a remote machine, using it to output remote information. When you should not use bash scripts your script is too long, as many as hundreds of lines you need more complex data structures than arrays there are complex escape problems there are too many string operations that do not need to invoke other programs and interact with other program pipelines to worry about performance
At this point, you should consider a scripting language, such as Python or Ruby. Reference Advanced bash-scripting Guide:http://tldp.org/ldp/abs/html/bash Reference Manual