关于符号 🔗
-
$
美元符号, 一般用于取变量的值, 不过总觉得和命令代换有很多相似之处, 具体可见样例, 另外美元符号也会和其他符号产生有意思的组合.$ var="echo hello" $ $var hello
-
[]
相当于test命令, 用于测试条件是否成立, 若成立则退出值为0(真), 由于if, for, case等结构语句通过上一条命令的退出值来决定运行流程, 因此方括号多用于这些结构语句中. -
$()
,` `
两种用法相同, 均是命令代换, 即取所包含的命令的输出作为文本值参与运行, 文本值甚至可以是命令, 如直接运行`echo pwd`
则相当于直接运行pwd
. -
$[]
对于此命令需要提前了解双反引号(上一条), 以及expr
命令,expr
官方描述为Print the value of EXPRESSION to standard output, 所以可以把expr
命令做命令代换, 于是$[]
与`expr expression`
效果相同, 样例如下.$ var1=`expr 1 + 1` $ var2=$[1 + 1] $ echo var1=$var1 var2=$var2 var1=2 var2=2
不过有一点奇怪的是, 以下命令的运行结果并不能如我所愿输出
hello
, 不过至少反引号和美元符号加方括号的行为是一样的, 仍然支持我的猜想.$ alias 2="echo hello" $ alias alias 2='echo hello' $ `expr 1 + 1` bash: 2: command not found $ $[1 + 1] bash: 2: command not found
-
;
可用于分隔命令, 书本上翻译为命令列表, 一般来说, 命令与命令之间通过换行符来进行分隔, 但是有时为了追求代码的紧凑会希望将几条命令放在同一行, 于是这便是分号的用途.if [ expression ] ; then command fi
-
()
用于表示数组, 数组样例见下一个符号的样例, 也用于进程列表, 进程列表中的命令会被开一个子shell运行, 进程列表样例如下.$ echo $BASH_SUBSHELL # 当前子shell水平为0 0 $ (echo $BASH_SUBSHELL) # 当前子shell水平为0 1
那么之前的命令代换中的括号是否也会被开一个子shell呢,
$ echo $BASH_SUBSHELL # 当前子shell水平为0 0 $ echo $(echo $BASH_SUBSHELL) # 命令代换中子shell水平为1 1
猜想得证.
-
${}
此符号用于取数组的值, 需要注意的一点是, 当数组中某一个位置的值被unset
之后, 该位置后面的值并不会自动向前移动一个序号, 可见样例.$ arr=( 1 2 3 ) $ echo ${arr[2]} 3 $ unset arr[1] $ echo ${arr[2]} 3 $ echo ${arr[1]} #空行, 无输出 $
-
[[ ]]
(( ))
双方括号是拓展字符运算, 双圆括号是拓展数学运算, 其中拓展数学运算可支持移位操作,自增操作等高级操作, 拓展字符运算可支持通配符匹配. -
;;
双分号用于case的匹配中, 与单分号不同的是, 单分号只能结束当前命令, 后续仍被认为是这一块的可执行语句, 不能接下一个匹配条件, 只有以双分号结尾, 才能接下一个匹配$ cat caseExample.sh var=2 case $var in 1 | 2 ) echo 1 ; echo 2 ;; 3 | 4 ) echo 3 ; echo 4 ;; esac $ ./caseExample.sh 1 2 $
关于结构化语句 🔗
-
if
判断语句-
判断的方法只是简单地根据上一命令的返回值来判断执行结构, 关于这一点, 其实最常用的方括号只是
test
命令, 这一点在上面符号的部分有提及. 通常用法是if command1 ; then command2 fi
以上用法中,
command1
是任意一个可执行的shell命令,command2
是条件为真则执行的语句体, 最后if
语句使用fi
进行结尾. 需要注意的是,command1
的返回值若是0
则if
判断为真, 非0
则判断为假, 这一点与许多类C语言恰恰相反. 另外,command1
是按照通常的命令执行方式执行的, 所以如果command1
命令有输出, 则会直接输出在控制台中. -
if
语句也可以在条件为假的时候执行语句, 方法是在结尾fi
之前加入一个else
; 当然if
也可以判断多个条件进行筛选, 方法是使用elfi
, 样例如下if command1 ; then command2 elif command3 ; then command4 else command5 fi
为了代码紧凑, 有时候会在判断命令之后使用分号进行分隔, 并把
then
放在同一行的之后 -
if
语句中也可以使用逻辑运算符, 和其他许多类C语言类似, 使用&&
,||
,!
, 分别作为与,或,非. 这些逻辑运算符可以用在test
命令和普通命令之中. 需要注意的是, 在test
手册中并没有&&
,||
的表述, 不过这些仍然被支持, 因为在shell中,&&
的行为是若该符号之前的命令运行的返回值为真, 则执行下一条命令,||
的行为是若该符号之前的命令运行返回值为假, 则执行下一条命令, 这个被称为"短路", 在C语言中同样适用. 所以如此来看的话, 使用command1 && command2
的作为分析, 如果command1
返回值为真, 则执行command2
, 此时整个逻辑表达式的值就由command2
的返回值决定, 若command2
的返回值也为真, 则最后$?
的值就是真, 反之则假. 若command1
返回值为假, 则短路, 最终整个逻辑运算的结果就是command1
的返回值–假. 原因是逻辑运算符的作用仅仅是决定是否进行短路, 而且条件判断依据仅仅是之前运行的最后一条命令的返回值, 于是整个逻辑运算十分顺利. 或运算同理. 至于非运算, 叹号!
其实也是一条命令, 这一点可以在终端不输入任何字符的情况下敲入双tab, 使其打印所有的可执行命令, 其中第一条就是!
. 样例如下$ ! echo 'hello' && echo 'true' ; echo $? hello 1 $ echo 'hello' && echo 'true' ; echo $? hello true 0 $ ! echo 'hello' || echo 'true' ; echo $? 'hello' 'true' 0
-
特殊变量 🔗
变量 | 含义 |
---|---|
$$ | 当前shell进程的PID |
$? | 上一命令运行的返回值 |
$# | 命令行脚本传递参数的个数 |
$@ | 作为数组(雾)获取全部命令行参数 |
$* | 作为一整条字符串获取全部命令行参数 |
$0 | 当前shell脚本的运行名(脚本的绝对路径或者相对路径) |
$n | shell脚本的第n个参数 |