()

命令组.在括号中的命令列表, 将会作为一个子shell来运行.
在括号中的变量,由于是在子shell中,所以对于脚本剩下的部分是不可用的. 父进程, 也就是脚本本身, 将不能够读取在子进程中创建的变量, 也就是在子shell中创建的变量.
(cmd1;cmd2;cmd3)

初始化数组.
Array=(element1 element2 element3)

$(...)

相当于`...`命令,返回括号中命令执行的结果

let命令


(( ))

(( ... ))结构可以用来计算并测试算术表达式的结果. 退出状态将会与[ ... ]结构完全相反!还可应用到c风格的for,while循环语句,(( )) 中,所有的变量(加不加$无所谓)都是数值。

$((...))结构的表达式是C风格的表达式,其返回的结果是表达式值,其中变量引用可不用‘$’(当然也可以)

for((...;...;...))
do
  cmd
done

while ((...))
do
  cmd
done

比较操作符

<

    小于

    (("$a" < "$b"))
<=

    小于等于

    (("$a" <= "$b"))
>

    大于

    (("$a" > "$b"))
>=

    大于等于

    (("$a" >= "$b"))


(( 0 ))
echo "Exit status of \"(( 0 ))\" is $?."         # 1

(( 1 ))
echo "Exit status of \"(( 1 ))\" is $?."         # 0

(( 5 > 4 ))                                      # 真
echo "Exit status of \"(( 5 > 4 ))\" is $?."     # 0

(( 5 > 9 ))                                      # 假
echo "Exit status of \"(( 5 > 9 ))\" is $?."     # 1

(( 5 - 5 ))                                      # 0
echo "Exit status of \"(( 5 - 5 ))\" is $?."     # 1

(( 5 / 4 ))                                      # 除法也可以.
echo "Exit status of \"(( 5 / 4 ))\" is $?."     # 0

(( 1 / 2 ))                                      # 除法的计算结果 < 1.
echo "Exit status of \"(( 1 / 2 ))\" is $?."     # 截取之后的结果为 0.
                                                  # 1

(( 1 / 0 )) 2>/dev/null                          # 除数为0, 非法计算. 
#          
echo "Exit status of \"(( 1 / 0 ))\" is $?."     # 1


for ((a=1; a <= LIMIT ; a++))  # 双圆括号, 并且"LIMIT"变量前面没有"$".
do
   echo -n "$a "
done 

while (( a <= LIMIT ))   # 双圆括号, 变量前边没有"$".
do
   echo -n "$a "
   ((a += 1))   # let "a+=1"
done

a=2
b=$(($a*4))     #a=2 b=8
c=$((a*3))      #a=2 c=6


[ ]

条件测试表达式放在[ ]中. 值得注意的是[是shell内建test命令的一部分, 并不是/usr/bin/test中的外部命令的一个链接.

文件测试操作符(如果下面的条件成立将会返回真)

-e

    文件存在(推荐用)
-a

    文件存在(不推荐用)

-f

    表示这个文件是一个一般文件(并不是目录或者设备文件)
-s

    文件大小不为零
-d

    表示这是一个目录
-b

    表示这是一个块设备(软盘, 光驱, 等等.) 
-c

    表示这是一个字符设备(键盘, modem, 声卡, 等等.)
-p

    这个文件是一个管道
-h

    这是一个符号链接
-L

    这是一个符号链接
-S

    表示这是一个socket
-t

    文件(描述符)被关联到一个终端设备上

    这个测试选项一般被用来检测脚本中的stdin([ -t 0 ]) 或者stdout([ -t 1 ])是否来自于一个终端. 
-r

    文件是否具有可读权限(指的是正在运行这个测试命令的用户是否具有读权限)
-w

    文件是否具有可写权限(指的是正在运行这个测试命令的用户是否具有写权限)
-x

    文件是否具有可执行权限(指的是正在运行这个测试命令的用户是否具有可执行权限)
-g

    set-group-id(sgid)标记被设置到文件或目录上

    如果目录具有sgid标记的话, 那么在这个目录下所创建的文件将属于拥有这个目录的用户组, 而不必是创建这个文件的用户组. 这个特性对于在一个工作组中共享目录非常有用. 

-u

    set-user-id (suid)标记被设置到文件上

    如果一个root用户所拥有的二进制可执行文件设置了set-user-id标记位的话, 那么普通用户也会以root权限来运行这个文件. [1] 这对于需要访问系统硬件的执行程序(比如pppd和cdrecord)非常有用. 如果没有suid标志的话, 这些二进制执行程序是不能够被非root用户调用的.

                  -rwsr-xr-t    1 root       178236 Oct  2  2000 /usr/sbin/pppd


    对于设置了suid标志的文件, 在它的权限列中将会以s表示. 
-k

    设置粘贴位

    对于"粘贴位"的一般了解, save-text-mode标志是一个文件权限的特殊类型. 如果文件设置了这个标志, 那么这个文件将会被保存到缓存中, 这样可以提高访问速度. [2] 粘贴位如果设置在目录中, 那么它将限制写权限. 对于设置了粘贴位的文件或目录, 在它们的权限标记列中将会显示t.

                  drwxrwxrwt    7 root         1024 May 19 21:26 tmp/

    如果用户并不拥有这个设置了粘贴位的目录, 但是他在这个目录下具有写权限, 那么这个用户只能在这个目录下删除自己所拥有的文件. 这将有效的防止用户在一个公共目录中不慎覆盖或者删除别人的文件. 比如说/tmp目录. (当然, 目录的所有者或者root用户可以随意删除或重命名其中的文件.) 

-O

    判断你是否是文件的拥有者
-G

    文件的group-id是否与你的相同
-N

    从文件上一次被读取到现在为止, 文件是否被修改过

f1 -nt f2

    文件f1比文件f2新
f1 -ot f2

    文件f1比文件f2旧
f1 -ef f2

    文件f1和文件f2是相同文件的硬链接
!

    "非" -- 反转上边所有测试的结果(如果没给出条件, 那么返回真).


比较操作符


整数比较

-eq

    等于

-ne

    不等于

-gt

    大于

-ge

    大于等于

-lt

    小于

-le

    小于等于


字符串比较

=

    等于

==

    等于,与=等价.(==比较操作符在双中括号对和单中括号对中的行为是不同的)

      [[ $a == z* ]]    # 如果$a以"z"开头(模式匹配)那么结果将为真
      [[ $a == "z*" ]]  # 如果$a与z*相等(就是字面意思完全一样), 那么结果为真.

      [ $a == z* ]      # 文件扩展匹配(file globbing)和单词分割有效. 
      [ "$a" == "z*" ]  # 如果$a与z*相等(就是字面意思完全一样), 那么结果为真. 

!=

    不等号(这个操作符将在[[ ... ]]结构中使用模式匹配)

<

    小于, 按照ASCII字符进行排序(注意"<"使用在[ ]结构中的时候需要被转义) 
>

    大于, 按照ASCII字符进行排序(注意">"使用在[ ]结构中的时候需要被转义)

-z

    字符串为"null", 意思就是字符串长度为零
-n

    字符串不为"null".

-a

    逻辑与

-o

    逻辑或


{xxx,yyy,zzz,...}

大括号扩展.
echo {1..20}
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
cat {file1,file2,file3} > combined_file
# 把file1, file2, file3连接在一起, 并且重定向到combined_file中.
cp file22.{txt,backup}
# 拷贝"file22.txt"到"file22.backup"中

在大括号中, 不允许有空白, 除非这个空白被引用或转义.

echo {file1,file2}\ :{\ A," B",' C'}

file1 : A file1 : B file1 : C file2 : A file2 : B file2 : C

代码块


这个结构事实上创建了一个匿名函数(一个没有名字的函数). 然而, 与"标准"函数不同的是, 在其中声明的变量,对于脚本其他部分的代码来说还是可见的(除了用declare,typeset命令声明的变量)


()会开启一个新的子shell,{}不会开启一个新的子shell

(())常用于算术运算比较,[[]]常用于字符串的比较.

$()返回括号中命令执行的结果

$(())返回的结果是括号中表达式值

${ }参数替换与扩展

参数替换

${var}
${var}=$var

${var:-default}    ${var-default}
如果var未set,那么就是用default.两者之间不同只有当var为空变量时,前者为default,后者为空.

${var:=default}    ${var=default}
如果var未set,那么就设置default.两者之间不同只有当var为空变量时,前者设置为default,后者设置为空.

${var:+default}    ${var+default}
如果var被set,就是用default.未set,就使用null字符串.两者之间不同只有当var为空变量时,前者为null字符串,后者为default.

上面三种参数替换中,第二种使用后变量的值被改变.

参数替换扩展

${#var}    ${#array}
字符串长度或数组第一个元素的字符串长度
例外:
${#*}、${#@}指位置参数的个数.
${#array  

  • },$[#array[@]}指数组元素的个数

    ${var#pattern}    ${var##pattern}
    从var开头删除最近或最远匹配pattern的子串.

    ${var%pattern}    ${var%%pattern}
    从var结尾删除最近或最远匹配pattern的子串.

    ${var:pos}
    变量var从位置pos开始扩展.

    ${var:pos:len}
    从位置pos开始,并扩展len长度个字符

    ${var/pattern/replacement}    ${var//pattern/replacement}
    使用replacement来替换var中的第一个或所有pattern的匹配.

    ${var/#pattern/replacement}
    如果var的前缀匹配到了pattern,那么就用replacement来替换pattern.

    ${var/%pattern/replacement}
    如果var的后缀匹配到了pattern,那么就用replacement来替换pattern.

    ${!varprefix*}    ${!varprefix@}
    前边所有声明过的,以varprefix为前缀的变量名.


    [[]]就是条件表达式,在bash中,字符串比较用  > < != == <= >= 只是在[]中 < >需要转义;对于数值比较.用 -lt -le -eq -ge -gt 来比较,与[[]]中表达不太一样,在[ ] 中的 < > 需要用转义 \< \>,如果有多个表达式,在[[ ]] 中用 && || 来组合,而[] 中是用 -a -o 来组合