下列每一个运算符在满足其下条件时,返回的结果为真
( -e )
检测文件是否存在
( -a )
检测文件是否存在
等价于 -e。不推荐使用,已被弃用。
( -f )
文件是常规文件(regular file),而非目录或 设备文件
( -s )
文件大小不为0
( -d )
文件是一个目录
( -b )
文件是一个 块设备
( -c )
文件是一个 字符设备
device0="/dev/sda2" # / (根目录)
if [ -b "$device0" ]
then
echo "$device0 is a block device."
fi
# /dev/sda2 是一个块设备。
device1="/dev/ttyS1" # PCMCIA 调制解调卡
if [ -c "$device1" ]
then
echo "$device1 is a character device."
fi
# /dev/ttyS1 是一个字符设备。
( -p )
文件是一个 管道设备
function show_input_type()
{
[ -p /dev/fd/0 ] && echo PIPE || echo STDIN
}
show_input_type "Input" # STDIN
echo "Input" | show_input_type # PIPE
( -h )
文件是一个 符号链接
( -L )
文件是一个符号链接
( -S )
文件是一个 套接字
( -t )
文件(文件描述符)与终端设备关联
该选项通常被用于 测试脚本中的 stdin [ -t 0 ]
或 stdout [ -t 1 ]
是否为终端设备
( -r )
该文件对执行测试的用户可读
( -w )
该文件对执行测试的用户可写
( -x )
该文件可被执行测试的用户所执行
( -g )
文件或目录设置了 set-group-id sgid 标志
如果一个目录设置了 sgid 标志,那么在该目录中所有的新建文件的权限组都归属于该目录的权限组,而非文件创建者的权限组。该标志对共享文件夹很有用
( -u )
文件设置了 set-user-id suid 标志。
一个属于 root 的可执行文件设置了 suid 标志后,即使是一个普通用户执行也拥有 root 权限。
对需要访问硬件设备的可执行文件(例如 pppd 和 cdrecord)很有用。
如果没有 suid 标志,这些可执行文件就不能被非 root 用户所调用了
-rwsr-xr-t 1 root 178236 Oct 2 2000 /usr/sbin/pppd
设置了 suid 标志后,在权限中会显示 s
( -k )
设置了粘滞位(sticky bit)
标志粘滞位是一种特殊的文件权限。如果文件设置了粘滞位,那么该文件将会被存储在高速缓存中以便快速访问。如果目录设置了该标记,那么它将会对目录的写权限进行限制,目录中只有文件的拥有者可以修改或删除文件。设置标记后你可以在权限中看到 t
drwxrwxrwt 7 root 1024 May 19 21:26 tmp/
如果一个用户不是设置了粘滞位目录的拥有者,但对该目录有写权限,那么他仅仅可以删除目录中他所拥有的文件。这可以防止用户不经意间删除或修改其他人的文件,例如 /tmp 文件夹。(当然目录的所有者可以删除或修改该目录下的所有文件)
( -O )
执行用户是文件的拥有者
( -G )
文件的组与执行用户的组相同
( -N )
文件在在上次访问后被修改过了
( f1 -nt f2 )
文件 f1 比文件 f2 新
( f1 -ot f2 )
文件 f1 比文件 f2 旧
( f1 -ef f2 )
文件 f1 和文件 f2 硬链接到同一个文件
( ! )
取反——对测试结果取反(如果条件缺失则返回真)
样例-1. 检测链接是否损坏
#!/bin/bash
# broken-link.sh
# Lee bigelow <ligelowbee@yahoo.com> 编写。
# ABS Guide 经许可可以使用。
# 该脚本用来发现输出损坏的链接。输出的结果是被引用的,
#+ 所以可以直接导到 xargs 中进行处理 :)
# 例如:sh broken-link.sh /somedir /someotherdir|xargs rm
#
# 更加优雅的方式:
#
# find "somedir" -type 1 -print0|\
# xargs -r0 file|\
# grep "broken symbolic"|
# sed -e 's/^\|: *broken symbolic.*$/"/g'
#
# 但是这种方法不是纯 Bash 写法。
# 警告:小心 /proc 文件下的文件和任意循环链接!
############################################
# 如果不给脚本传任何参数,那么 directories-to-search 设置为当前目录
#+ 否则设置为传进的参数
#####################
[ $# -eq 0 ] && directory=`pwd` || directory=$@
# 函数 linkchk 是用来检测传入的文件夹中是否包含损坏的链接文件,
#+ 并引用输出他们。
# 如果文件夹中包含子文件夹,那么将子文件夹继续传给 linkchk 函数进行检测。
#################
linkchk () {
for element in $1/*; do
[ -h "$element" -a ! -e "$element" ] && echo \"$element\"
[ -d "$element" ] && linkchk $element
# -h 用来检测是否是链接,-d 用来检测是否是文件夹。
done
}
# 检测传递给 linkchk() 函数的参数是否是一个存在的文件夹,
#+ 如果不是则报错。
################
for directory in $direcotrys; do
if [ -d $directory ]
then linkchk $directory
else
echo "$directory is not a directory"
echo "Usage $0 dir1 dir2 ..."
fi
done
exit $?
其他比较操作
二元比较操作比较变量或者数量。注意整数和字符串比较使用的是两套运算符
整数比较
( -eq )
等于
if [ "$a" -eq "$b" ]
( -ne )
不等于
if [ "$a" -ne "$b" ]
-gt )
大于
if [ "$a" -gt "$b" ]
( -ge )
大于等于
if [ "$a" -ge "$b" ]
( -lt )
小于
if [ "$a" -lt "$b" ]
( -le )
小于等于
if [ "$a" -le "$b" ]
( < )
小于(使用 双圆括号)
(("$a" < "$b"))
( <= )
小于等于(使用双圆括号)
(("$a" <= "$b"))
( > )
大于(使用双圆括号)
(("$a" > "$b"))
( >= )
大于等于(使用双圆括号)
(("$a" >= "$b"))
字符串比较
( = )
等于
if [ "$a" = "$b" ]
注意在 = 前后要加上空格
if [ "$a"="$b" ] 和上面不等价
( == )
等于
if [ "$a" == "$b" ]
和 =
同义 ==
运算符在 双方括号和单方括号里表现不同
[[ $a == z* ]] # $a 以 "z" 开头时为真(模式匹配)
[[ $a == "z*" ]] # $a 等于 z* 时为真(字符匹配)
[ $a == z* ] # 发生文件匹配和字符分割。
[ "$a" == "z*" ] # $a 等于 z* 时为真(字符匹配)
( != )
不等于
if [ "$a" != "$b" ]
在 [[ ... ]]
结构中会进行模式匹配。
( < )
小于,按照 ASCII码
排序
if [[ "$a" < "$b" ]]
if [ "$a" \< "$b" ]
注意在 []
结构里 <
需要被 转义
( > )
大于,按照 ASCII 码排序
if [[ "$a" > "$b" ]]
if [ "$a" \> "$b" ]
注意在 []
结构里 >
需要被转义
( -z )
字符串为空,即字符串长度为0
String='' # 长度为0的字符串变量。
if [ -z "$String" ]
then
echo "\$String is null."
else
echo "\$String is NOT null."
fi # $String is null.
( -n )
字符串非空(null)
使用 -n
时字符串必须是在括号中且被引用的
使用 ! -z
判断未引用的字符串或者直接判断 通常可行,但是非常危险
判断字符串时一定要引用
样例-2. 算术比较和字符串比较
#!/bin/bash
a=4
b=5
# 这里的 "a" 和 "b" 可以是整数也可以是字符串。
# 因为 Bash 的变量是弱类型的,因此字符串和整数比较有很多相同之处。
# 在 Bash 中可以用处理整数的方式来处理全是数字的字符串。
# 但是谨慎使用。
echo
if [ "$a" -ne "$b" ]
then
echo "$a is not equal to $b"
echo "(arithmetic comparison)"
fi
echo
if [ "$a" != "$b" ]
then
echo "$a is not equal to $b."
echo "(string comparison)"
# "4" != "5"
# ASCII 52 != ASCIII 53
fi
# 在这个例子里 "-ne" 和 "!=" 都可以。
echo
exit 0
样例-3. 测试字符串是否为空(null)
#!/bin/bash
# str-test.sh: 测试是否为空字符串或是未引用的字符串。
# 使用 if [ ... ] 结构
# 如果字符串未被初始化,则其值是未定义的。
# 这种状态就是空 "null"(并不是 0)。
if [ -n $string1 ] # 并未声明或是初始化 string1。
then
echo "String \"string1\" is not null."
else
echo "String \"string1\" is null."
fi
# 尽管没有初始化 string1,但是结果显示其非空。
echo
# 再试一次。
if [ -n "$string1" ] # 这次引用了 $string1。
then
echo "String \"string1\" is not null."
else
echo "String \"string1\" is null."
fi # 在测试括号内引用字符串得到了正确的结果。
echo
if [ $string1 ] # 这次只有一个 $string1。
then
echo "String \"string1\" is not null."
else
echo "String \"string1\" is null."
fi # 结果正确。
# 独立的 [ ... ] 测试运算符可以用来检测字符串是否为空。
# 但是最好将字符串进行引用(if [ "$string1" ])。
#
# Stephane Chazelas 指出:
# if [ $string1 ] 只有一个参数 "]"
# if [ "$string1" ] 则有两个参数,空的 "$string1" 和 "]"
echo
string1=initialized
if [ $string1 ] # $string1 这次仍然没有被引用。
then
echo "String \"string1\" is not null."
else
echo "String \"string1\" is null."
fi # 这次的结果仍然是正确的。
# 最好将字符串引用("$string1")
string1="a = b"
if [ $string1 ] # $string1 这次仍然没有被引用。
then
echo "String \"string1\" is not null."
else
echo "String \"string1\" is null."
fi # 这次没有引用就错了。
exit 0
样例-4. zmore
#!/bin/bash
# zmore
# 使用筛选器 'more' 查看 gzipped 文件。
E_NOARGS=85
E_NOTFOUND=86
E_NOTGZIP=87
if [ $# -eq 0 ] # 作用和 if [ -z "$1" ] 相同。
# $1 可以为空: zmore "" arg2 arg3
then
echo "Usage: `basename $0` filename" >&2
# 将错误信息通过标准错误 stderr 进行输出。
exit $E_NOARGS
# 脚本的退出状态为 85.
fi
filename=$1
if [ ! -f "$filename" ] # 引用字符串以防字符串中带有空格。
then
echo "File $filename not found!" >&2 # 通过标准错误 stderr 进行输出。
exit $E_NOTFOUND
fi
if [ ${filename##*.} != "gz" ]
# 在括号内使用变量代换。
then
echo "File $1 is not a gzipped file!"
exit $E_NOTGZIP
fi
zcat $1 | more
# 使用筛选器 'more'
# 也可以用 'less' 替代
exit $? # 脚本的退出状态由管道 pipe 的退出状态决定。
# 实际上 "exit $?" 不一定要写出来,
#+ 因为无论如何脚本都会返回最后执行命令的退出状态。
复合比较
( -a )
逻辑与
exp1 -a exp2 返回真当且仅当 exp1 和 exp2 均为真
( -o )
逻辑或
如果 exp1
或 exp2
为真,则 exp1 -o exp2
返回真。
以上两个操作和 双方括号结构中的 Bash 比较运算符号 &&
和 ||
类似
[[ condition1 && condition2 ]]
测试操作 -o
和 -a
可以在 test
命令或在测试括号中进行
if [ "$expr1" -a "$expr2" ]
then
echo "Both expr1 and expr2 are true."
else
echo "Either expr1 or expr2 is false."
fi
rihad 指出:
[ 1 -eq 1 ] && [ -n "`echo true 1>&2`" ] # 真
[ 1 -eq 2 ] && [ -n "`echo true 1>&2`" ] # 没有输出
# ^^^^^^^ 条件为假。到这里为止,一切都按预期执行。
# 但是
[ 1 -eq 2 -a -n "`echo true 1>&2`" ] # 真
# ^^^^^^^ 条件为假。但是为什么结果为真?
# 是因为括号内的两个条件子句都执行了么?
[[ 1 -eq 2 && -n "`echo true 1>&2`" ]] # 没有输出
# 并不是。
# 所以显然 && 和 || 具备“短路”机制,
#+ 例如对于 &&,若第一个表达式为假,则不执行第二个表达式直接返回假,
#+ 而 -a 和 -o 则不是。
网友评论