1. Shell各种易混淆的括号和指令
1.1. 单引号,双引号和反向单引号
- 单引号会把其里面的内容完全当做字符串来进行处理,不对任何特殊字符包括
${}引用变量符号进行处理- 注意这里
$和${}本质没有区别,都是引用变量符号,这里为了便于理解用了${}而已,下同 - 同时这里注意,如果是在一些命令后面,比如
echo后面的单引号内部的内容;如果针对这个命令有一些参数选项,比如说echo -e,则不论是单引号还是双引号,其里面的转义字符\还是会进行转义处理的,只是在单引号里面的命令和引用变量的符号不进行处理而已,比如${}引用变量命令等等。
- 注意这里
- 双引号则是不执行其中包含的命令,但是会对其内部的变量引用符号
${}进行处理 - 而反向单引号则是会优先处理并执行其中的所有内容,包括命令和引用变量等等。
- 反向单引号等价
$()
- 反向单引号等价
[04:56:19 root@Centos6 ~]# echo echo $PS1 这里不加任何引号和双引号效果一样,都是只处理变量引用
echo [\[\e[1;42m\]\t \u@\h \e[0m\w]\$
[05:06:39 root@Centos6 ~]# echo 'echo $PS1'
echo $PS1
[05:06:53 root@Centos6 ~]# echo "echo $PS1"
echo [\[\e[1;42m\]\t \u@\h \e[0m\w]\$
[05:07:00 root@Centos6 ~]# echo `echo $PS1` 这里先把反向单引号内的命令执行之后再执行外面的echo命令
[\[\e[1;42m\]\t \u@\h \e[0m\w]\$
[05:07:08 root@Centos6 ~]# echo -e 'echo \n $PS1' 这里就是上面说的加了-e参数后,转义字符就算在单引号里面也会执行,只不过命令和变量引用还是不会执行
echo
$PS1
[05:07:46 root@Centos6 ~]# echo -e "echo \n $PS1" 而这里则可以看出,当加了-e选项后,因为双引号内的变量PS1会被处理成其原本的含义,则可以看做是 echo -e "echo \n [\[\e[1;42m\]\t \u@\h \e[0m\w]\$" ,所以里面的所有的转义字符只要是符合echo的参数的都会被执行
echo
[\[\] \u@\h \w]\$
[05:07:55 root@Centos6 ~]# echo -e `echo \n $PS1` 这里结合下面的命令可知也就相当于执行了echo -e "n n [\[\e[1;42m\]\t \u@\h \e[0m\w]\$"
n [\[\] \u@\h \w]\$
[05:09:44 root@Centos6 ~]# echo \n $PS1
n [\[\e[1;42m\]\t \u@\h \e[0m\w]\$
2. 整体注意点总结
- 利用小括号开启subshell的时候,其执行命令的返回值是最后一个命令的返回值;
- 中括号(当前shell)也同上,也是最后一个命令的返回值;
3. 小括号,圆括号()
3.1. 单小括号 ()
( cmd1;cmd2;...)命令组(它属于bash中的Grouping Commands,同类的包含两外一个,也就是花括号{})。- 括号中的命令将会新开一个子shell顺序执行,所以括号中的变量不能够被脚本余下的部分使用(局部变量无法在父进程shell中使用)。
- 但是注意小括号是对父进程(shell)的duplicate的一个子shell,就是为了运行其中的命令而已,所以默认保留了父进程的所有变量,只有当子shell对变量进行重新修改或者赋值的时候,其内的变量内容才会改变,否则就和父进程的变量相同,具体参考bash的command execution environment一部分章节。
- 括号中多个命令之间用分号隔开,最后一个命令可以没有分号,各命令和括号之间不必有空格。
- 括号中的命令将会新开一个子shell顺序执行,所以括号中的变量不能够被脚本余下的部分使用(局部变量无法在父进程shell中使用)。
$(cmd1;cmd2;...)命令替换(它属于bash中的七大扩展之一 Command Substitution)。- 等同于
cmd,shell扫描一遍命令行,发现了$(cmd)结构,便将$(cmd)中的cmd执行一次,得到其标准输出,再将此输出放到原来命令中。有些shell不支持,如tcsh。
- 等同于
用于初始化数组。
- 如:array=(a b c d)
3.2. 双小括号 (( ))
(( expression算术表达式 )):(算术)整数扩展(它属于bash中的条件判断结构Conditional Constructs,同类的还有if,case,select以及双中括号这另外的4个语句)。- 这种扩展计算是整数型的计算,不支持浮点型。
- 由它的在bash中的分类可知,仅仅是双小括号,前面不带有
$符号时,它主要目的就是为了将其内部的算术表达式扩展并判断结果,然后返回一个true或false; (( expression ))结构扩展并计算一个算术表达式的值,如果表达式的数值结果不为0,那么返回“真”,其返回的退出状态码为0,在bash中表现就是echo $?=0- 如果表达式的数值结果为0,那么返回“假”,其返回的退出状态码为1,在bash中表现就是
echo $?=1 - 它完全等价于
let "expression"
- 特殊用法:
- 单纯用 (( )) 也可修改变量数值,比如 a=5; ((a++)) 可将
$a的内容数值改为6 - 这其实还是利用它本身的(算术)整数扩展功能而已
- 单纯用 (( )) 也可修改变量数值,比如 a=5; ((a++)) 可将
$(( expression算术表达式 )):算术扩展(它则属于bash中的八大扩展之一 Arithmetic Expansion)- 它的目的是将其内的算术表达式进行计算结果之后,将结果输出到原来的位置;
- 它并不是用于判断返回值的,和不加
$符号时候用于条件判断的目的完全不同 - 只要括号中的运算符、表达式符合C语言运算规则,都可用在
$((exp))中,甚至是三目运算符。这些运算符的优先级,结合性和代表的意义和C语言中的完全相同; - 作不同进位(如二进制、八进制、十六进制)运算时,输出结果全都自动转化成了十进制。如:echo $((16#5f)) 结果为95 (16进位转十进制)
3.3. 双小括号(不加$)注意点:
- 双小括号中(不论是
((还是$(()中由于都是进行的数值运算,所以其中的字符串都会被看做是变量名(也因此变量前面不用加$符号),当这个字符串(也就是变量名)没有被赋值或者说赋值了但是是字符串类型的,在双小括号中进行运算时都会被当做0来处理。 - 双小括号(不加
$符号)常用于算术运算比较,参见下面附上的的bash中的arithmetic原版解释; - 由于它支持C语言的运算符,C语言里面的
< >等等比较数值大小的运算符这里面也可以使用,可以并且仅可以用来比较数值的大小,不能用于字符串 - 双小括号中的变量可以不使用$符号前缀(当然加上也不算错)。
- 因此双小括号内的不以数字开头的字符串都会被看做是一个变量(其他的情况比如两个字符串,以数字开头字符结尾的字符串等等会报错),看这个变量的值是什么来判断返回结果
- 如果是字符串或者数值0或者没有赋值,则返回错误1;如果是不为0的数值,则返回正确0;
- 括号内支持多个表达式用逗号分开。
- 只要括号中的表达式符合C语言运算规则,就可以使用;
- 比如配合for循环语句结构,可以直接使用for((i=0;i<5;i++));
- 如果不使用双括号, 则为for i in
seq 0 4或者for i in {0..4}; - 再如可以直接使用
if (($i<5)), 如果不使用双括号, 则为if [ $i -lt 5 ]。
- 附加知识点:if条件判断结构,其中
if test-commands;then cmd;fi,只要test-commands命令的返回值是true,在bash中也就是0,那么就会执行then后面的语句。- 也就是说,这里进行if判断的时候,只看
test-commands命令执行的返回值,而并不看这命令本身执行的结果
- 也就是说,这里进行if判断的时候,只看
3.4. 一定要注意双小括号和(双)中括号的区别:
- (双)中括号适用于条件测试,双小括号适用于各种算术扩展进行计算;
- 它俩的目的都是使用它们的返回值进行下一步的判断等操作,但是计算返回值的方式不同;双小括号是判断内部的算术表达式计算之后的结果的数值是否不为0,不为0则范围值为正确;而(双)中括号的条件判断则有很多;
- (双)中括号条件测试有:1.判断文件相关信息等等,2.比较字符串的sort顺序前后,以及3.数值比较大小;(双)中括号条件测试的数值比较大小只能用
-gt -ge -eq -ne -lt -le6个符号;同时条件测试的返回结果 - 双小括号里只能用于数值相关的计算,可以用
<>等符号(下面看原版介绍),不能用于比较字符串sort顺序,判断文件属性等 等。
3.5. (())和$(())的区别
- 它俩都可以用来进行赋值运算,不过有区别:
- 双小括号:
((a=3+4)) - 加上符号:
a=$((3+4))
- 双小括号:
(())可以用来进行数值之间的判断,参考下面的原版解释,举例--------------------------------- (( a == 8)) ---------------------------------- # (( \!1 )); echo $? 1 # (( 1 )); echo $? 0 # (( \!0 )); echo $? 0 # 这里!前面加上\是为了不和历史命令!history_CMD冲突 ----------------------------------
- 关于双小括号内的算术表达式,bash中的Shell Arithmetic,也就是arithmetic expression的原版解释:
The shell allows arithmetic expressions to be evaluated, as one of the shell expansions or by using the (( compound command, the let builtin, or the -i option to the declare builtin.
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. The following list of operators is grouped into levels of equal-precedence operators. The levels are listed in order of decreasing precedence.
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 variable 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. When specifying n, 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.
Operators are evaluated in order of precedence. Sub-expressions in parentheses are evaluated first and may override the precedence rules above.
4. 2.中括号,方括号[]
4.1. 单双中括号的许多用法基本都是一样的,双中括号由于能适用更多符号和更多功能,所以更常用,可以完全用它替代单中括号。
4.2. 1.单中括号 []
test 条件判断表达式 或 [ 条件判断表达式 ]:bash 的内部命令,[和test是等同的。(它属于bash的Bourne Shell Builtins 内部命令分类中)Test和[]中可用的比较运算符参考下面的原版条件判断表达式conditional expression;- 其中需要注意的就是
> < ==和!=,它们都是用于字符串比较的,不可用于整数比较;整数比较只能使用-eq,-gt这种形式。 - 字符串比较大小(在单中括号中就是比较字符串在ASCII的排序顺序),注意这里的
< >要使用转义形式,比如比较"ab"和"bc":[ ab \< bc ],结果为真,也就是返回状态为0。 [ ]中的逻辑与和逻辑或使用-a和-o表示。[ string ]不写任何参数直接写字符串的时候,等价于[-n "string"],下面的双中括号[[ ]]是也一样的逻辑;
字符范围。用作通配符pattern matching或者正则表达式的一部分,描述一个匹配的字符范围。代表匹配其内部任意一个字符;
- 作为test用途的单中括号内使用正则,它里面只能是条件判断表达式。
在一个数组array 结构的上下文中,中括号用来引用数组中每个元素的编号。
4.3. 2.双中括号[[ ]]
[[ 条件判断表达式]]: 它属于bash中的条件判断结构Conditional Constructs,同类的还有if,case,select以及双小括号这另外的4个语句[[是 bash 程序语言的关键字。并不是一个命令,[[ ]] 结构比[ ]结构更加通用。在[[和]]之间所有的字符都不会发生文件名扩展或者单词分割,但是会发生参数扩展和命令替换等。它支持字符串的模式匹配,使用=~操作符时甚至支持shell的正则表达式。字符串比较时可以把右边的作为一个模式,而不仅仅是一个字符串,比如
[[ hello == hell? ]],结果为真。- 注意
[[ ]]中匹配字符串或通配符或正则表达式,它右边的匹配的内容(包括模式pattern和正则表达式)不需要且不能加单或者双引号。如果加了引号则完全变成了字符串了;比如[[ hello == "hell?" ]],结果为假 - 但建议条件判断表达式左边的的内容比如变量等,加上双引号,避免变量没有定义或者赋值导致的问题出现;比如
[[ "$Var" == hell? ]],这种写法是比较标准的 - 除非有一种情况,就是中括号内的判断符号左右两边都是变量的情况下,为了避免变量没有被赋值,此时需要左右两边都需要加上双引号;其他的情况一般就是左边是变量(不论是位置变量$1这种还是普通变量),需要加上双引号,右边是pattern或者expression,不需要也不能加上双引号。
- 注意
使用
[[ ... ]]条件判断结构,而不是[ ... ],能够防止脚本中的许多逻辑错误。- 比如,
&&、||、<和>操作符能够正常存在于[[ ]]条件判断结构中,但是如果出现在[ ]结构中的话,会报错 - 当然单中括号里面的
< >也不是说不能用,可以转义使用,用于比较字符串ASCII码表顺序;但双括号里面的< >就是比较字符串sort顺序的(根据当前current locale),注意它即使被转义了也只能代表普通的符号,不能和=~配合使用当做正则表达式的词首词尾锚定来用了!) - 比如说,可以直接使用
if [[ $a != 1 && $a != 2 ]](!=的优先级高于&&,虽然conditional expression里面没写,但是C语言的算术表达式里把它们的优先级的顺序给写明了,和C语言一样的;如果觉得不能确定优先级,那就用小括号括起来提升优先级,改为if [[ ($a != 1) && ($a != 2) ]]), - 如果不使用双括号, 则为
if [ $a -ne 1] && [ $a != 2 ]或者if [ $a -ne 1 -a $a != 2 ]。
- 比如,
[[ string ]]不写任何参数直接写字符串的时候,等价于[[-n "string"]],和上面的单中括号[]是一样的逻辑;附加知识点:这里双中括号里面的
&&或||或和双括号外面的&&或||(比如上面举例中的if中的)&&并不是一个含义:- 1.双中括号里面的
&&或者||是双中括号特有的条件判断的符号(单中括号不能用这两个符号,但可以用-a或-o类似替代);2.它的左右两边写的都是条件判断的表达式;3.双中括号内被看做是一个整体,它的返回值就是&&或||符号左右两边条件判断表达式的返回值的整体(根据符号不同判断不同的结果);4.它是根据&&或||符号从左往右,判断条件判断表达式的返回值是否为真(也就是$?=0),然后再继续往右进行判断,直到能判断式子整体的返回值。 - 1.命令行的
&&或||符号是命令列表(commands of list)中的符号,它是属于一系列命令的结合;2.它的左右两边写的就是普通的命令(当然也可以是条件判断表达式,比如if [ $a -ne 1] && [ $a != 2 ]就是利用了这个 );3.它并不是看做一个整体,它的返回值是整个式子最后一个执行的普通命令(或者条件判断表达式)的返回值;4.同样它也是根据&&或||符号从左往右,判断普通命令执行的返回值是否为真(也就是$?=0),(这里注意是命令执行的返回值而并不是命令本身执行的结果,所以这里也可以使用条件判断表达式,因为条件判断表达式目的也是为了使用它的返回值)然后再继续往右进行命令的执行,直到根据&&或||符号判断出不需要再进行下一个命令的执行。 - 注意不论是双中括号内的还是命令列表,都是从左往右直到无需再进行判断之后,后面的命令或者条件判断表达式就不再进行执行或者判断了;
- 1.双中括号里面的
在
[[]]使用==,在[]使用=,可以用于数字大小,但实际上是把它看做的字符串来进行比较的,真正用于比较字符串大小得用那6个参数bash把双中括号中的表达式看作一个单独的元素,并返回一个退出状态码。同时
$$和||符号,从左往右如果能判断结果的话,后面的条件判断表达式就不再进行进一步的判断了,这点要注意
4.4. 单双中括号注意点:
[[]]中左侧的变量加双引号,右侧匹配内容不加双引号是最标准写法,如果加上双引号就被强行转换为字符串string了,上面已经说明。- 不论是单还是双中括号,都不能用
<> ==(或=) 或 !=来判断数值的大小,因为这4个是比较字符串的,并且是按照ASCII(单中括号)或sort(双中括号)来比较的 - 想要比较数值的大小:
- 要么在单或者双中括号内使用那6个数值比较大小的参数
-gt -ge -eq -ne -lt -le - 要么就使用双小括号
(( 算术表达式 )),它里面专门用于数值的各种计算比较并返回结果;看上面的部分可知。
- 要么在单或者双中括号内使用那6个数值比较大小的参数
- 无论是单中括号还是双中括号,其内容中判断的都是条件判断表达式返回值的结果,虽然它俩中间的内容都可以执行命令(command substitution),但是不能用命令执行的返回值结果来进行结果的判断;比如下面进行一些举例:------------------------------------ 1. 下面就是相当于省略了-n,它就是一个判断内容是否为空字符串的条件判断表达式,只要内容不为空,其结果都是返回真; # [ hostname ] ; echo $? 0 ------------------------------------ 2. 这里hostname命令执行之后,结果仍然是字符串,相当于和1中的情形是一样的,仍然是省略了-n的条件判断表达式而已;所以返回值仍然为真;加上-z用来对比-n; # [ `hostname` ] ; echo $? 0 # [ -z `hostname` ] ; echo $? 1 ------------------------------------ 3. 这里虽然hostname执行了,但是由于把它的结果给重定向了,相当于命令执行后仍旧为空,那么由于它还是相当于省略了-n的条件判断表达式,因此它的返回值就是假。加上-z 也可以看出区别。 # [ `hostname > /dev/null` ] ; echo $? 1 # [ -z `hostname > /dev/null` ] ; echo $? 0 ----------------------------------- 4. 接3,由于echo命令没有输出任何值,所以它的返回值也是假; # [ echo ] ;echo $? 0 # [ `echo` ] ;echo $? 1 ------------------------------------ 5. 这里由于命令执行错误,所以返回值为假的 # [ `hostna` ] ; echo $? bash: hostna: command not found... 1 ------------------------------------ 6. 这里不论是单括号的-a 还是双括号的 &&等符号,由于中括号的大原则也就是只能判断条件判断表达式,则它判断结果的时候: 1. 如果符号两边都是条件判断表达式,则会根据条件判断表达式的结果一步一步往后判断 2. 如果符号两边是命令,则会把命令执行的结果当做字符串省略了-n的格式(仍然是一个条件判断表达式)来进行判断。 - 结合上面5个就可以知道下面的各个结果的原因 # [[ `hostname` && `echo` ]] ;echo $? 1 # [[ `hostname` && `echo2` ]] ;echo $? bash: echo2: command not found... Similar command is: 'echo' 1 # [[ `hostname` && `echo 1` ]] ;echo $? 0 ---------------- # [ `hostname` -a `echo 1` ] ;echo $? 0 # [ `hostname` -a `echo` ] ;echo $? -bash: [: cet: unary operator expected 2 # [ `hostname` -a "`echo`" ] ;echo $? 0 # [ `hostname` -a "" ] ;echo $? 1 # [ `hostname` -a `echo2` ] ;echo $? bash: echo2: command not found... Similar command is: 'echo' -bash: [: cet: unary operator expected 2 # [ `hostname` -a `echo 2` ] ;echo $? 0
各种小例子:
if (( $i<5 ))
if [ $i -lt 5 ]
if [ $a -ne 1 -a $a != 2 ]
if [ $a -ne 1] && [ $a != 2 ]
if [[ $a != 1 && $a != 2 ]]
for i in $(seq 0 4);do echo $i;done
for i in `seq 0 4`;do echo $i;done
for ((i=0;i<5;i++));do echo $i;done
for i in {0..4};do echo $i;done
- 这里附上**1.命令列表(Lists of Commands) 2.test(单中括号)3.双中括号 4.条件判断(conditional expression)**的原版bash解释
Lists of Commands 命令列表
A list is a sequence of one or more pipelines separated by one of the operators ‘;’, ‘&’, ‘&&’, or ‘||’, and optionally terminated by one of ‘;’, ‘&’, or a newline.
Of these list operators, ‘&&’ and ‘||’ have equal precedence, followed by ‘;’ and ‘&’, which have equal precedence.
A sequence of one or more newlines may appear in a list to delimit commands, equivalent to a semicolon.
If a command is terminated by the control operator ‘&’, the shell executes the command asynchronously in a subshell. This is known as executing the command in the background, and these are referred to as asynchronous commands. The shell does not wait for the command to finish, and the return status is 0 (true). When job control is not active (see Job Control), the standard input for asynchronous commands, in the absence of any explicit redirections, is redirected from /dev/null.
Commands separated by a ‘;’ are executed sequentially; the shell waits for each command to terminate in turn. The return status is the exit status of the last command executed.
AND and OR lists are sequences of one or more pipelines separated by the control operators ‘&&’ and ‘||’, respectively. AND and OR lists are executed with left associativity.
An AND list has the form
command1 && command2
command2 is executed if, and only if, command1 returns an exit status of zero (success).
An OR list has the form
command1 || command2
command2 is executed if, and only if, command1 returns a non-zero exit status.
The return status of AND and OR lists is the exit status of the last command executed in the list.
--------------------------------------------
Bourne Shell Builtins 内部变量 test部分:
test
[
test expr
Evaluate a conditional expression expr and return a status of 0 (true) or 1 (false). Each operator and operand must be a separate argument. Expressions are composed of the primaries described below in Bash Conditional Expressions. test does not accept any options, nor does it accept and ignore an argument of -- as signifying the end of options.
When the [ form is used, the last argument to the command must be a ].
Expressions may be combined using the following operators, listed in decreasing order of precedence. The evaluation depends on the number of arguments; see below. Operator precedence is used when there are five or more arguments.
! expr
True if expr is false.
( expr )
Returns the value of expr. This may be used to override the normal precedence of operators.
expr1 -a expr2
True if both expr1 and expr2 are true.
expr1 -o expr2
True if either expr1 or expr2 is true.
The test and [ builtins evaluate conditional expressions using a set of rules based on the number of arguments.
0 arguments
The expression is false.
1 argument
The expression is true if, and only if, the argument is not null.
2 arguments
If the first argument is ‘!’, the expression is true if and only if the second argument is null. If the first argument is one of the unary conditional operators (see Bash Conditional Expressions), the expression is true if the unary test is true. If the first argument is not a valid unary operator, the expression is false.
3 arguments
The following conditions are applied in the order listed.
If the second argument is one of the binary conditional operators (see Bash Conditional Expressions), the result of the expression is the result of the binary test using the first and third arguments as operands. The ‘-a’ and ‘-o’ operators are considered binary operators when there are three arguments.
If the first argument is ‘!’, the value is the negation of the two-argument test using the second and third arguments.
If the first argument is exactly ‘(’ and the third argument is exactly ‘)’, the result is the one-argument test of the second argument.
Otherwise, the expression is false.
4 arguments
If the first argument is ‘!’, the result is the negation of the three-argument expression composed of the remaining arguments. Otherwise, the expression is parsed and evaluated according to precedence using the rules listed above.
5 or more arguments
The expression is parsed and evaluated according to precedence using the rules listed above.
When used with test or ‘[’, the ‘<’ and ‘>’ operators sort lexicographically using ASCII ordering.
------------------------------------
条件判断结构Conditional Constructs 双中括号部分:
[[…]]
[[ expression ]]
Return a status of 0 or 1 depending on the evaluation of the conditional expression expression. Expressions are composed of the primaries described below in Bash Conditional Expressions. Word splitting and filename expansion are not performed on the words between the [[ and ]]; tilde expansion, parameter and variable expansion, arithmetic expansion, command substitution, process substitution, and quote removal are performed. Conditional operators such as ‘-f’ must be unquoted to be recognized as primaries.
When used with [[, the ‘<’ and ‘>’ operators sort lexicographically using the current locale.
When the ‘==’ and ‘!=’ operators are used, the string to the right of the operator is considered a pattern and matched according to the rules described below in Pattern Matching, as if the extglob shell option were enabled. The ‘=’ operator is identical to ‘==’. If the nocasematch shell option (see the description of shopt in The Shopt Builtin) is enabled, the match is performed without regard to the case of alphabetic characters. The return value is 0 if the string matches (‘==’) or does not match (‘!=’) the pattern, and 1 otherwise. Any part of the pattern may be quoted to force the quoted portion to be matched as a string.
An additional binary operator, ‘=~’, is available, with the same precedence as ‘==’ and ‘!=’. When it is used, the string to the right of the operator is considered a POSIX extended regular expression and matched accordingly (as in regex3)). The return value is 0 if the string matches the pattern, and 1 otherwise. If the regular expression is syntactically incorrect, the conditional expression’s return value is 2. If the nocasematch shell option (see the description of shopt in The Shopt Builtin) is enabled, the match is performed without regard to the case of alphabetic characters. Any part of the pattern may be quoted to force the quoted portion to be matched as a string. Bracket expressions in regular expressions must be treated carefully, since normal quoting characters lose their meanings between brackets. If the pattern is stored in a shell variable, quoting the variable expansion forces the entire pattern to be matched as a string. Substrings matched by parenthesized subexpressions within the regular expression are saved in the array variable BASH_REMATCH. The element of BASH_REMATCH with index 0 is the portion of the string matching the entire regular expression. The element of BASH_REMATCH with index n is the portion of the string matching the nth parenthesized subexpression.
For example, the following will match a line (stored in the shell variable line) if there is a sequence of characters in the value consisting of any number, including zero, of space characters, zero or one instances of ‘a’, then a ‘b’:
[[ $line =~ [[:space:]]*?(a)b ]]
That means values like ‘aab’ and ‘ aaaaaab’ will match, as will a line containing a ‘b’ anywhere in its value.
Storing the regular expression in a shell variable is often a useful way to avoid problems with quoting characters that are special to the shell. It is sometimes difficult to specify a regular expression literally without using quotes, or to keep track of the quoting used by regular expressions while paying attention to the shell’s quote removal. Using a shell variable to store the pattern decreases these problems. For example, the following is equivalent to the above:
pattern='[[:space:]]*?(a)b'
[[ $line =~ $pattern ]]
If you want to match a character that’s special to the regular expression grammar, it has to be quoted to remove its special meaning. This means that in the pattern ‘xxx.txt’, the ‘.’ matches any character in the string (its usual regular expression meaning), but in the pattern ‘"xxx.txt"’ it can only match a literal ‘.’. Shell programmers should take special care with backslashes, since backslashes are used both by the shell and regular expressions to remove the special meaning from the following character. The following two sets of commands are not equivalent:
pattern='\.'
[[ . =~ $pattern ]]
[[ . =~ \. ]]
[[ . =~ "$pattern" ]]
[[ . =~ '\.' ]]
The first two matches will succeed, but the second two will not, because in the second two the backslash will be part of the pattern to be matched. In the first two examples, the backslash removes the special meaning from ‘.’, so the literal ‘.’ matches. If the string in the first examples were anything other than ‘.’, say ‘a’, the pattern would not match, because the quoted ‘.’ in the pattern loses its special meaning of matching any single character.
Expressions may be combined using the following operators, listed in decreasing order of precedence:
( expression )
Returns the value of expression. This may be used to override the normal precedence of operators.
! expression
True if expression is false.
expression1 && expression2
True if both expression1 and expression2 are true.
expression1 || expression2
True if either expression1 or expression2 is true.
The && and || operators do not evaluate expression2 if the value of expression1 is sufficient to determine the return value of the entire conditional expression.
----------------------------------------
条件判断表达式 Bash Conditional Expressions :
Conditional expressions are used by the [[ compound command and the test and [ builtin commands. The test and [ commands determine their behavior based on the number of arguments; see the descriptions of those commands for any other command-specific actions.
Expressions may be unary or binary, and are formed from the following primaries. Unary expressions are often used to examine the status of a file. There are string operators and numeric comparison operators as well. Bash handles several filenames specially when they are used in expressions. If the operating system on which Bash is running provides these special files, Bash will use them; otherwise it will emulate them internally with this behavior: If the 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.
When used with [[, the ‘<’ and ‘>’ operators sort lexicographically using the current locale. The test command uses ASCII ordering.
Unless otherwise specified, primaries that operate on files follow symbolic links and operate on the target of the link, rather than the link itself.
-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 its set-group-id bit is set.
-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. The list of options appears in the description of the -o option to the set builtin (see The Set Builtin).
-v varname
True if the shell variable varname is set (has been assigned a value).
-R varname
True if the shell variable varname is set and is a name reference.
-z string
True if the length of string is zero.
-n string
string
True if the length of string is non-zero.
string1 == string2
string1 = string2
True if the strings are equal. When used with the [[ command, this performs pattern matching as described above (see Conditional Constructs).
‘=’ 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, respectively. Arg1 and arg2 may be positive or negative integers. When used with the [[ command, Arg1 and Arg2 are evaluated as arithmetic expressions (see Shell Arithmetic).
5. 大括号、花括号 {}
5.1. 常规用法
大括号拓展。(通配(globbing))将对大括号中的文件名做扩展。在大括号中,不允许有空白,除非这个空白被引用或转义。第一种:对大括号中的以逗号分割的文件列表进行拓展。如 touch {a,b}.txt 结果为a.txt b.txt。第二种:对大括号中以点点(..)分割的顺序文件列表起拓展作用,如:touch {a..d}.txt 结果为a.txt b.txt c.txt d.txt
# ls {ex1,ex2}.sh ex1.sh ex2.sh # ls {ex{1..3},ex4}.sh ex1.sh ex2.sh ex3.sh ex4.sh # ls {ex[1-3],ex4}.sh ex1.sh ex2.sh ex3.sh ex4.sh代码块,又被称为内部组,这个结构事实上创建了一个匿名函数 。与小括号中的命令不同,大括号内的命令不会新开一个子shell运行,即脚本余下部分仍可使用括号内变量。括号内的命令间用分号隔开,最后一个也必须有分号。{}的第一个命令和左括号之间必须要有一个空格。
5.2. 几种特殊的替换结构
${var:-string},${var:+string},${var:=string},${var:?string}
${var:-string}和${var:=string}:若变量var为空,则用在命令行中用string来替换{var:-string};对于{var:-string}是一样的,所不同之处是{var:=string}的同时,把string赋给变量var: ${var:=string}很常用的一种用法是,判断某个变量是否赋值,没有的话则给它赋上一个默认值。${var:+string}的替换规则和上面的相反,即只有当var不是空的时候才替换成string,若var为空时则不替换或者说是替换成变量 var的值,即空值。(因为变量var此时为空,所以这两种说法是等价的)${var:?string}替换规则为:若变量var不为空,则用变量var的值来替换${var:?string};若变量var为空,则把string输出到标准错误中,并从脚本中退出。我们可利用此特性来检查是否设置了变量的值。补充扩展:在上面这五种替换结构中string不一定是常值的,可用另外一个变量的值或是一种命令的输出。
5.3. 四种模式匹配替换结构
模式匹配记忆方法:
# 是去掉左边(在键盘上#在$之左边)
% 是去掉右边(在键盘上%在$之右边)
#和%中的单一符号是最小匹配,两个相同符号是最大匹配。
${var%pattern}
${var%%pattern}
${var#pattern}
${var##pattern}
第一种模式:
${variable%pattern},这种模式时,shell在variable中查找,看它是否一给的模式pattern结尾,如果是,就从命令行把variable中的内容去掉右边最短的匹配模式第二种模式:
${variable%%pattern},这种模式时,shell在variable中查找,看它是否一给的模式pattern结尾,如果是,就从命令行把variable中的内容去掉右边最长的匹配模式第三种模式:
${variable#pattern}这种模式时,shell在variable中查找,看它是否一给的模式pattern开始,如果是,就从命令行把variable中的内容去掉左边最短的匹配模式第四种模式:
${variable##pattern}这种模式时,shell在variable中查找,看它是否一给的模式pattern结尾,如果是,就从命令行把variable中的内容去掉右边最长的匹配模式
- 这四种模式中都不会改变variable的值,其中,只有在pattern中使用了*匹配符号时,%和%%,#和##才有区别。结构中的pattern支持通配符,*表示零个或多个任意字符,?表示仅与一个任意字符匹配,[…]表示匹配中括号里面的字符,[!…]表示不匹配中括号里面的字符。
# var=testcase
# echo $var
testcase
# echo ${var%s*e}
testca
# echo $var
testcase
# echo ${var%%s*e}
te
# echo ${var#?e}
stcase
# echo ${var##?e}
stcase
# echo ${var##*e}
# echo ${var##*s}
e
# echo ${var##test}
case
5.4. 字符串提取和替换
${var:num}
${var:num1:num2}
${var/pattern/pattern}
${var//pattern/pattern}
第一种模式:
${var:num},这种模式时,shell在var中提取第num个字符到末尾的所有字符。若num为正数,从左边0处开始;若num为负数,从右边开始提取字串,但必须使用在冒号后面加空格或一个数字或整个num加上括号,如{var:1-3}或${var:(-2)}。第二种模式:
${var:num1:num2},num1是位置,num2是长度。表示从num1个位置开始提取长度为$num2的子串。不能为负数。第三种模式:
${var/pattern/pattern}表示将var字符串的第一个匹配的pattern替换为另一个pattern。第四种模式:
${var//pattern/pattern}表示将var字符串中的所有能匹配的pattern替换为另一个pattern。
[root@centos ~]# var=/home/centos
[root@centos ~]# echo $var
/home/centos
[root@centos ~]# echo ${var:5}
/centos
[root@centos ~]# echo ${var: -6}
centos
[root@centos ~]# echo ${var:(-6)}
centos
[root@centos ~]# echo ${var:1:4}
home
[root@centos ~]# echo ${var/o/h}
/hhme/centos
[root@centos ~]# echo ${var//o/h}
/hhme/cenths
6. 符号$后的括号
${a}变量a的值, 在不引起歧义的情况下可以省略大括号。$(cmd)命令替换,和cmd效果相同,结果为shell命令cmd的输,过某些Shell版本不支持$()形式的命令替换, 如tcsh。$((expression))和exprexpression效果相同, 计算数学表达式exp的数值, 其中exp只要符合C语言的运算规则即可, 甚至三目运算符和逻辑表达式都可以计算。
7. 补充知识点
7.1. 使用多条命令执行
- 单小括号,
(cmd1;cmd2;cmd3)新开一个子shell顺序执行命令cmd1,cmd2,cmd3, 各命令之间用分号隔开, 最后一个命令后可以没有分号。 - 单大括号,
{ cmd1;cmd2;cmd3;}在当前shell顺序执行命令cmd1,cmd2,cmd3, 各命令之间用分号隔开, 最后一个命令后必须有分号, 第一条命令和左括号之间必须用空格隔开。
- 对
{}和()而言, 括号中的重定向符只影响该条命令, 而括号外的重定向符影响到括号中的所有命令。
留言
Njfhsjdwkdjwfh jiwkdwidwhidjwi jiwkdowfiehgejikdoswfiw https://gehddijiwfugwdjaidheufeduhwdwhduhdwudw.com/fjhdjwksdehfjhejdsdefhe
Нello all, guуѕǃ Ι knоw, mу mеssаge mау be tоo ѕрecіfіc, But my ѕіѕtеr found nісe mаn hеrе and thеу mаrriеd, ѕо hоw about mе?ǃ 🙂 I аm 24 yеarѕ old, Саtherinа, from Romаnіа, Ι knоw Εnglish аnd German lаnguаges аlso Αnd… Ι have ѕресific disеаѕe, nаmеd nуmphomanіа. Who knоw what іs this, сan undеrѕtand mе (bettеr tо ѕay it іmmеdіatеlу) Аh уеѕ, I cоok very taѕty! and Ι love not оnly сook ;)) Ιm rеal girl, not prostіtutе, аnd lоokіng for ѕеriоus аnd hоt rеlatіоnship… Αnywаy, уоu саn find mу рrofіle hеrе: http://konsburwolfwatch.tk/user/23178/
Waiting patiently for you to come home and fuck me! http://bitly.ws/znHX
Waiting patiently for you to come home and fuck me! http://bitly.ws/znHX
你好! 对于过于具体的消息,我深表歉意。 我和我的女朋友彼此相爱。 我们都很棒。 但是……我们需要一个男人。 我们 25 岁,来自罗马尼亚,我们也懂英语。 我们永远不会觉得无聊! 不仅在谈话中… 我的名字是 阿莲娜,我的个人资料在这里:http://presinicwebsens.cf/item-77551/
Waiting patiently for you to come home and fuck me! http://bitly.ws/znHX
Waiting patiently for you to come home and fuck me! http://bitly.ws/znHX
Something for all the boobie lovers…. http://prephe.ro/Bdsn
大家好,伙计们! 我知道,我的信息可能过于具体, 但是我姐姐在这里找到了好男人,他们结婚了,那我呢?! 🙂 我24 岁,玛丽亚,来自罗马尼亚,我也懂英语和德语 并且… 我有一种特殊的疾病,叫做色情狂。 谁知道这是什么,能理解我(最好马上说) 啊,是的,我做的很好吃! 我不仅爱做饭;)) 我是真正的女孩,不是妓女,并且正在寻找严肃而火辣的关系…… 无论如何,你可以在这里找到我的个人资料:http://bornthecom.ga/idm-45292/
你好! 我注意到很多男人更喜欢普通的女孩。 我为那些有能力享受许多女人的爱的男人鼓掌,并选择了一个他知道在颠簸和疯狂的生活中将成为他最好的朋友的男人。 我想成为那个朋友,而不仅仅是一个稳定、可靠和无聊的家庭主妇。 我今年 27 岁,纳塔利娅,来自捷克共和国,也懂英语。 无论如何,你可以在这里找到我的个人资料:http://windnonddoubkins.tk/idl-74706/