bash中的括号

作者: lesca 分类: Tutorials,Ubuntu 发布时间: 2011-10-09 18:29

bash语法并没有什么复杂,但是里面很多用法严格苛刻到离谱的符号用法却让很多人学了就忘。可是这是有历史原因的,可以说,shell脚本是其他很多脚本的鼻祖。
本文以现今最流行的bash shell作为平台,例举并分类了应用中经常碰到的括号。相信熟练掌握这些括号之后,离shell大师又走进了一步。希望读者能够学有所获!

一、括号与bash语句

1.子语句

(list)
list将在一个子shell中被执行,不会对当前shell产生影响
返回list的exit值

{ list; }
list前后必须有空格
可以作组合命令用
list将在当前shell中被执行
list结尾处必须要有新行或’;’号
返回list的exit值

2.用花括号进行枚举

{list} 用于枚举
如touch {a,b,c}将创建3个文件

3. ((expression))

算术表达式求值
如((p=p+1)),不需要$符号
echo $((3+2)) 将输出5
echo $((p++))
算术比较
((1>2)) 比较大小
((1==1)) 比较是否相等(注意使用双等号)
(($p<=5))

4.小括号与花括号一起使用,构成函数

f(){…} 函数
函数名前没有返回类型,括号中也没有参数
参数通过$0..n传入
举例:

die()
{
    m=$1
    echo $m
    exit
}

二、中括号——强大的条件测试工具

1.旧版本 [ condition ]
condition 前后必须有空格(因为符号[是一个命令)
变量名前$符号不可省略

1.什么时候判断为false?

NULL为false
[ $x ] 未声明或未初始化的变量x为false
注意:
未声明是指上文中从未出现的变量
未初始化是指出现但是没有赋值的变量
初始化为NULL
x=
x=””
[ $x ] 初始化为NULL的变量为false
反例:
[ x ] 这里x是字符串,判断为true

2.“非”运算符!

非运算符可以在中括号内,中括号外,甚至与其他语句一起使用。

if [ ! -r "$file" ] ; then 
    die "$file is unreadable."
fi

将非运算放到中括号外效果一样,如

if ! [ -r "$file" ]

也可以和其他语句一起使用,如grep,用于判断是否存在指定行:

if ! grep "^email=*" "$file" > /dev/null; then
    die "Please edit $file and setup email address"
fi

3.文件测试

-e 文件存在
-f 表示这个文件是一个一般文件(并不是目录或者设备文件)
-s 文件大小size>0
-d 表示这是一个目录
-b 表示这是一个块设备(软盘, 光驱, 等等.)
-c 表示这是一个字符设备(键盘, modem, 声卡, 等等.)
-p 这个文件是一个管道
-L 这是一个符号链接
-S 表示这是一个socket

-r 运行这个测试命令的用户是否具有读权限
-w 运行这个测试命令的用户是否具有写权限
-x 运行这个测试命令的用户是否具有可执行权限

-u set-user-id (suid)标记被设置到文件上
-g set-group-id(sgid)标记被设置到文件或目录上
-k 设置粘贴位sticky

-O 判断你是否是文件的拥有者
-G 文件的group-id是否与你的相同
-N 从文件上一次被读取到现在为止, 文件是否被修改过
f1 -nt f2 文件f1比文件f2新
f1 -ot f2 文件f1比文件f2旧
f1 -ef f2 文件f1和文件f2是相同文件的硬链接

4.字符串测试

= 等于
== 等于 与=等价
!= 不等号
-z 字符串为”zero”(字符串不存在)
-n 字符串为non-zero(字符串存在)
< 小于, 按照ASCII字符进行排序 > 大于, 按照ASCII字符进行排序
if [[ “$a” > “$b” ]]
if [ “$a” \> “$b” ]
注意“>”使用在[ ]结构中的时候需要被转义.

5.算术测试

-eq 等于
-ne 不等于
-gt 大于
-ge 大于等于
-lt 小于
-le 小于等于

6.举例

变量存在时执行:

if [ "$p" ] ; then
	expression
elif [ condition ]; then
	expression
else
	expression
fi

更为简单的形式:

[ "$p" ] && echo "$p existed"
可以写成更为规范的形式:
[ -n "$p" ] && echo "$p existed"

变量不存在时执行:

[ "$1" ] || echo "$1 non-existed" 
更为规范的形式:
[ -n "$1" ] || echo "$1 non-existed" 
[ -z "$1" ] && echo "$1 non-existed" 

获取参数

while [ $# -gt 0 ]; do
    case "$1" in  
    -e )
        arg1=$1
        shift ;;

    # errors
    * ) break ;;
    esac
shift
done

2.新版本 [[ condition ]]
condition 前后必须有空格
[[是一个关键字, 并不是一个命令
在版本2.02的Bash中, 引入了[[ … ]]扩展测试命令
比较运算符为<, >, =(注意不是 == )
比较运算符前后必须有空格
举例:

[[ $a < $b ]] && echo b  比较变量的大小(可以是数字或字符串)
[[ a < b ]] && echo b 比较字符串的大小(显然a<b成立)
[[ $a = $b ]] 判断这两个变量是否相等(注意只要一个等号)

三、花括号与变量

要引用一个变量,有两种方式:
$var
${var}
它们两者是等价的。第二种形式使得bash对变量名有更多修饰的机会。下面将对此展开讨论。

1.条件变量

以下表达式中p是变量名,word是字符串
${p:-word}如果变量p不存在,返回"word"
${p:=word}如果变量p不存在,返回"word",并将p的值设为"word"
${p:?word}如果变量p不存在,将"word"打入STDERR
${p:+word}如果变量p存在,返回"word"

2.子字符串

export p="hello"
${p:2}返回llo
${p:2:1}返回l
${#p}返回p的长度5

3.截取字符串

${p#pattern}返回p开头删除pattern后的字符串,非贪婪模式
${p##pattern}返回p开头删除pattern后的字符串,贪婪模式
${p%pattern}返回p结尾删除pattern后的字符串,非贪婪模式
${p%%pattern}返回p结尾删除pattern后的字符串,贪婪模式

举例:

$ echo $p
hellollollo
$ echo ${p%llo*}
hellollo
$ echo ${p%%llo*}
he

$ echo $p
lolololvictory
$ echo ${p#*o}
lololvictory
$ echo ${p##*o}
ry

下面是一个提取email中username的脚本,它还展示了如何从文件读取email列表

export file="email"
cat "$file" | while read line; do
    username=${line%@*}
    touch $username
done

4.字符串替换

${p/pattern/word}用"word"替换pattern,pattern前可加#或%,表开头或结尾
${p//pattern/word}用"word"替换所有pattern,pattern前可加#或%,表开头或结尾
举例:

$ export p="hello"

$ echo ${p//l/a}
heaao

$ echo $p
hello

注意,这只影响输出,但是不改变变量固有的值
如果希望将某个文件中的所有模式%NAME%替换成指定变量$name则可以使用sed工具:

sed "s/%NAME%/$name/g" "$file" > ${name}

5.二重参数

export p=HOME
${!p}等价于$HOME
${!p*}返回所有以p开头的变量名
举例:

$ echo ${!P*}
PATH PIPESTATUS PPID PS1 PS2 PS4 PWD

版权声明

本文出自 Lesca 技术宅,转载时请注明出处及相应链接。

本文永久链接: https://www.lesca.cn/archives/bash-brackets.html

如果觉得我的文章对您有用,请随意赞赏。您的支持将鼓励我继续创作!

2 Comments
  • 刀尖红叶

    2012-04-22 at 10:01

    受益匪浅,谢谢了!

  • 初学者

    2015-03-24 at 11:14

    谢谢作者