Linux Shell

Linux Shell

约定(DEFINITIONS)
The following definitions are used throughout the rest of this document.

1
2
3
4
5
6
7
8
9
10
11
12
13
blank  A space or tab.
word A sequence of characters considered as a single unit by the shell. Also
known as a token.
name A word consisting only of alphanumeric characters and underscores, and
beginning with an alphabetic character or an underscore. Also referred to
as an identifier.
metacharacter
A character that, when unquoted, separates words. One of the following:
| & ; ( ) < > space tab
control operator
A token that performs a control function. It is one of the following sym‐
bols:
|| & && ; ;; ( ) | |& <newline>

Shell 参数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
Special Parameters
The shell treats several parameters specially. These parameters may only be referenced; assignment to them is not allowed.
`*` Expands to the positional parameters, starting from one. When the expansion occurs within double quotes, it expands to a single word with the value of each parameter separated by the first character of the `IFS` special variable. That is, **"`$*`" is equivalent to `"$1c$2c..."`**, where `c` is the first character of the value of the `IFS` variable. If `IFS` is unset, the parameters are separated by spaces. If `IFS` is null, the parameters are joined without intervening separators.
`@` Expands to the positional parameters, starting from one. When the expansion occurs within double quotes, each parameter expands to a separate word. That is, **"`$@`" is equivalent to `"$1" "$2" ...`** If the double-quoted expansion occurs within a word, the expansion of the first parameter is joined with the beginning part of the original word, and the expansion of the last parameter is joined with the last part of the original word. When there are no positional parameters, "$@" and $@ expand to nothing (i.e., they are removed).
`#` Expands to the number of positional parameters in decimal.
`?` Expands to the exit status of the most recently executed foreground pipeline.
`-` Expands to the current option flags as specified upon invocation, by the set builtin command, or those set by the shell itself (such as the -i option).
`$` Expands to the process ID of the shell. In a () subshell, it expands to the process ID of the current shell, not the subshell.
`!` Expands to the process ID of the most recently executed background (asynchronous) command.
`0` Expands to the name of the shell or shell script. This is set at shell initialization. If bash is invoked with a file of commands, $0 is set to the name of that file. If bash is started with the -c option, then $0 is set to the first argument after the string to be executed, if one is present. Otherwise, it is set to the file name used to invoke bash, as given by argument zero.
`_` At shell startup, set to the absolute pathname used to invoke the shell or shell script being executed as passed in the environment or argument list. Subsequently, expands to the last argument to the previous command, after expansion. Also set to the full pathname used to invoke each command exe cuted and placed in the environment exported to that command. When checking mail, this parameter holds the name of the mail file currently being checked.

`$0` : 脚本名称

`$1-9` : 脚本执行时的参数1到参数9

`$?` : 脚本返回值

`$#` : 脚本执行时,输入参数个数

`$@` : 输入的参数的具体内容(将输入的参数作为一个多个对象,即是所有参数的一个列表)

`$*` : 输入的参数的具体内容(将输入的参数整体看作一个字符串)

`$$` : Shell本身的PID(ProcessID,即脚本运行的当前进程ID号)

`$!` : Shell最后运行的后台Process的PID(后台运行的最后一个进程的进程ID号)

`$-` : 显示shell使用的当前选项,与set命令功能相同


单引号、双引号以及没有引号的区别

  • 单引号:
    可以说是所见即所得:即将单引号内的内容原样输出,或者描述为单引号里面看见的是什么就会输出什么。

  • 双引号:
    把双引号内的内容输出出来;如果内容中有命令,变量等,会先把变量,命令解析出结果,然后在输出最终内容来。
    双引号内命令或变量的写法为命令或变量或$(命令或变量)。

  • 无引号:
    把内容输出出来,不会将含有空格的字符串视为一个整体输出;
    如果内容中有命令、变量等,会先把变量、命令解析结果,然后在输出最终内容来;
    如果字符串中带有空格等特殊字符,则不能完整的输出,需要改加双引号,一般连续的字符串,数字,路径等可以用,不过最好用双引号替代之


条件表达式(CONDITIONAL EXPRESSIONS)

Conditional expressions are used by the [[ compound command and the test and [
builtin commands to test file attributes and perform string and arithmetic com‐
parisons. Expressions are formed from the following unary or binary primaries.
If any file argument to one of the primaries is of the form /dev/fd/n, then file
descriptor n is checked. If the file argument to one of the primaries is one of
/dev/stdin, /dev/stdout, or /dev/stderr, file descriptor 0, 1, or 2,
respectively, is checked.

Unless otherwise specified, primaries that operate on files follow symbolic links
and operate on the target of the link, rather than the link itself.

When used with [[, the < and > operators sort lexicographically(字典顺序) using
the current locale. The test command sorts using ASCII ordering.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
-a file
True if file exists.
-b file
True if file exists and is a block special file.
-c file
True if file exists and is a character special file.
-d file
True if file exists and is a directory.
-e file
True if file exists.
-f file
True if file exists and is a regular file.
-g file
True if file exists and is set-group-id.
-h file
True if file exists and is a symbolic link.
-k file
True if file exists and its ``sticky'' bit is set.
-p file
True if file exists and is a named pipe (FIFO).
-r file
True if file exists and is readable.
-s file
True if file exists and has a size greater than zero.
-t fd True if file descriptor fd is open and refers to a terminal.
-u file
True if file exists and its set-user-id bit is set.
-w file
True if file exists and is writable.
-x file
True if file exists and is executable.
-G file
True if file exists and is owned by the effective group id.
-L file
True if file exists and is a symbolic link.
-N file
True if file exists and has been modified since it was last read.
-O file
True if file exists and is owned by the effective user id.
-S file
True if file exists and is a socket.
file1 -ef file2
True if file1 and file2 refer to the same device and inode numbers.
file1 -nt file2
True if file1 is newer (according to modification date) than file2, or if
file1 exists and file2 does not.
file1 -ot file2
True if file1 is older than file2, or if file2 exists and file1 does not.
-o optname
True if the shell option optname is enabled. See the list of options
under the description of the -o option to the set builtin below.
-v varname
True if the shell variable varname is set (has been assigned a value).
-z string
True if the length of string is zero.
string
-n string
True if the length of string is non-zero.

string1 == string2
string1 = string2
True if the strings are equal. = should be used with the test command for
POSIX conformance.

string1 != string2
True if the strings are not equal.

string1 < string2
True if string1 sorts before string2 lexicographically.

string1 > string2
True if string1 sorts after string2 lexicographically.

arg1 OP arg2
OP is one of `-eq, -ne, -lt, -le, -gt, or -ge`. These arithmetic binary
operators return true if arg1 is equal to, not equal to, less than, less
than or equal to, greater than, or greater than or equal to arg2, respec‐
tively. Arg1 and arg2 may be positive or negative integers.

算术求值(ARITHMETIC EVALUATION)

The shell allows arithmetic expressions to be evaluated, under certain circumstances(情景) (see the let and declare builtin commands and Arithmetic Expansion).
Evaluation is done in fixed-width integers with no check for overflow, though division by 0 is trapped and flagged as an error.
The operators and their precedence, associativity, and values are the same as in the C language.
运算符及其优先级,关联性和值与C语言中的相同。

The following list of operators is grouped into levels of equal-precedence operators.
The levels are listed in order of decreasing precedence.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
id++ id--
variable post-increment and post-decrement
++id --id
variable pre-increment and pre-decrement
- + unary minus and plus
! ~ logical and bitwise negation
** exponentiation(幂)
* / % multiplication, division, remainder
+ - addition, subtraction
<< >> left and right bitwise shifts
<= >= < >
comparison
== != equality and inequality
& bitwise AND
^ bitwise exclusive OR
| bitwise OR
&& logical AND
|| logical OR
expr?expr:expr
conditional operator
= *= /= %= += -= <<= >>= &= ^= |=
assignment
expr1 , expr2
comma

Shell variables are allowed as operands; parameter expansion is performed before
the expression is evaluated. Within an expression, shell variables may also be
referenced by name without using the parameter expansion syntax. A shell vari‐
able that is null or unset evaluates to 0 when referenced by name without using
the parameter expansion syntax. The value of a variable is evaluated as an
arithmetic expression when it is referenced, or when a variable which has been
given the integer attribute using declare -i is assigned a value. A null value
evaluates to 0. A shell variable need not have its integer attribute turned on
to be used in an expression.

Constants with a leading 0 are interpreted as octal numbers.A leading 0x or 0X
denotes hexadecimal. Otherwise, numbers take the form [base#]n,
where the optional base is a decimal number between 2 and 64
representing the arithmetic base, and n is a number in that base. If base#
is omitted, then base 10 is used.

1
2
3
4
5
6
7
e.g.:
[test@localhost ~]$ echo "$((012+7))" #8进制的12加上10进制的7,等于10进制的17
17
[test@localhost ~]$ echo "$((0xA+7))" #16进制的A加上10进制的7,等于10进制的17
17
[test@localhost ~]$ echo "$((4#13+7))" #4进制的13加上10进制的7,等于10进制的14
14

The digits greater than 9 are represented by the lowercase letters, the uppercase
letters, @, and _, in that order. If base is less than or equal to 36, lowercase
and uppercase letters may be used interchangeably to represent numbers between 10
and 35
.

64进制: 10个数字(09)+26个小写(az)+26个大写(A~Z)+1个@+1个_。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
e.g.:
[test@localhost ~]$ echo "$((36#a))" #36进制的a,等于10进制的10
10
[test@localhost ~]$ echo "$((36#A))" #36进制的A,等于10进制的10
10
[test@localhost ~]$ echo "$((37#a))" #37进制的a,等于10进制的10
10
[test@localhost ~]$ echo "$((37#A))" #37进制的A,等于10进制的36
36
[test@localhost ~]$ echo "$((64#Z))" #64进制的Z,等于10进制的61
61
[test@localhost ~]$ echo "$((64#@))" #64进制的@,等于10进制的62
62
[test@localhost ~]$ echo "$((64#_))" #64进制的_,等于10进制的63
63

Operators are evaluated in order of precedence. Sub-expressions in parentheses
are evaluated first and may override the precedence rules above.
按优先顺序评估运算符。 首先评估括号中的子表达式,并可以覆盖上面的优先级规则。


算术扩展(Arithmetic Expansion)

Arithmetic expansion allows the evaluation of an arithmetic expression and the
substitution of the result. The format for arithmetic expansion is:

   ``$((expression))``  

The expression is treated as if it were within double quotes, but a double quote
inside the parentheses is not treated specially. All tokens in the expression
undergo parameter expansion, string expansion, command substitution, and quote
removal. Arithmetic expansions may be nested.

The evaluation is performed according to the rules listed below under ARITHMETIC
EVALUATION. If expression is invalid, bash prints a message indicating failure
and no substitution occurs.


循环

for name [ [ in [ word ... ] ] ; ] do list ; done

1
2
3
4
5
6
7
8
#e.g.:
sum=0
for i in {1..100};do
if [ $[$i%3] -eq 0 ];then #相除取余进行判定
let sum+=$i #进行加法运算
fi
done
echo $sum

for (( expr1 ; expr2 ; expr3 )) ; do list ; done
The arithmetic expression expr1, expr2 expr3.

1
2
3
4
5
#e.g.:
for ((i=1;i<10;i++))
do
echo $i
done

select name [ in word ] ; do list ; done

case word in [ [(] pattern [ | pattern ] ... ) list ;; ] ... esac

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
#e.g.:
function usage(){
echo "Usage: $0 [start|stop|restart]"
}
function main()
{
if [[ $# -ne 1 ]]; then
usage;
exit 0;
fi

case $1 in
"start" )
echo "word: start."
;;
"stop" )
echo "word: stop."
;;
"restart" )
echo "word: restart."
;;
*)
echo "word: $1."
;;
esac
}
main $@

if list; then list; [ elif list; then list; ] ... [ else list; ] fi

1
2
3
4
5
6
7
8
9
10
11
#e.g.:
a=1
b=2
if [[ a=b ]];then
echo "a equal b.";
elif [[ a=1 ]];then
echo "a is 1";
elif [[ b=1 ]];then
echo "b is 1";
fi
#res: a equal b.

while list-1; do list-2; done
until list-1; do list-2; done

1
2
3
4
5
6
7
8
#e.g.:
u=0
i=1
while [ $i -le 100 ] ;do
let u+=i
let i+=2
done
echo $u

数组(Arrays)

Bash provides one-dimensional indexed and associative array variables.
Any variable may be used as an indexed array; the declare builtin will explicitly declare
an array. There is no maximum limit on the size of an array, nor any requirement
that members be indexed or assigned contiguously(连续). Indexed arrays are referenced
using integers (including arithmetic expressions) and are zero-based;
associative arrays are referenced using arbitrary(随意) strings.

An indexed array is created automatically if any variable is assigned to using
the syntax name[subscript]=value. The subscript is treated as an arithmetic
expression that must evaluate to a number. If subscript evaluates to a number
less than zero, it is used as an offset from one greater than the array’s maximum
index (so a subcript of -1 refers to the last element of the array). To explicitly
declare an indexed array, use declare -a name (see SHELL BUILTIN COMMANDS
below). declare -a name[subscript] is also accepted; the subscript is ignored.

Associative arrays are created using declare -A name.

Attributes may be specified for an array variable using the declare and readonly
builtins. Each attribute applies to all members of an array.

Arrays are assigned to using compound assignments of the form name=(value1 ...valuen),
where each value is of the form [subscript]=string. Indexed array
assignments do not require the bracket and subscript. When assigning to indexed
arrays, if the optional brackets and subscript are supplied, that index is
assigned to; otherwise the index of the element assigned is the last index
assigned to by the statement plus one. Indexing starts at zero.

When assigning to an associative array, the subscript is required.

This syntax is also accepted by the declare builtin. Individual array elements
may be assigned to using the name[subscript]=value syntax introduced above.

Any element of an array may be referenced using ${name[subscript]}. The braces
are required to avoid conflicts with pathname expansion.
If subscript is @ or *,
the word expands to all members of name. These subscripts differ only when the
word appears within double quotes. If the word is double-quoted, ${name[*]}
expands to a single word with the value of each array member separated by the
first character of the IFS special variable, and ${name[@]} expands each element
of name to a separate word. When there are no array members, ${name[@]} expands
to nothing. If the double-quoted expansion occurs within a word, the expansion
of the first parameter is joined with the beginning part of the original word,and
the expansion of the last parameter is joined with the last part of the original word.
This is analogous to the expansion of the special parameters * and @
(see Special Parameters ). ${#name[subscript]} expands to the length of
${name[subscript]}. If subscript is * or @, the expansion is the number of
elements in the array. Referencing an array variable without a subscript is
equivalent to referencing the array with a subscript of 0.

An array variable is considered set if a subscript has been assigned a value.
The null string is a valid value.

The unset builtin is used to destroy arrays. unset name[subscript] destroys the
array element at index subscript. Care must be taken to avoid unwanted side
effects caused by pathname expansion. unset name, where name is an array, or
unset name[subscript], where subscript is * or @, removes the entire array.

The declare, local, and readonly builtins each accept a -a option to specify an
indexed array and a -A option to specify an associative array. If both options
are supplied, -A takes precedence(优先). The read builtin accepts a -a option to
assign a list of words read from the standard input to an array. The set and
declare builtins display array values in a way that allows them to be reused as
assignments.

1
2
3
4
5
6
7
8
9
10
e.g.:
[test@localhost ~]$ declare -a arr=("hello" "," "world" '!');echo ${arr[0]} #echo数组下标为[0]的元素
hello
[test@localhost ~]$ declare -a arr=("hello" "," "world" '!');echo ${#arr[0]} #echo数组下标为[0]的元素的长度
5
[test@localhost ~]$ declare -a arr=("hello" "," "world" '!');echo ${#arr[*]} #echo数组元素个数
4
[test@localhost ~]$ declare -a arr=("hello" "," "world" '!');echo ${arr[*]} #echo数组所有元素
hello , world !


参考

  • Linux Manual.