高级Bash脚本编程指南(7):文件测试操作符

高级Bash脚本编程指南(7):文件测试操作符

成于坚持,败于止步

如果下面的条件成立将会返回真.

-e
文件存在
-a
文件存在,这个选项的效果与-e相同. 但是它已经被"弃用"了, 并且不鼓励使用.
-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用户调用的.对于设置了suid标志的文件, 在它的权限列中将会以s表示.其实这个权限在最初说文件权限的文章中已经说过了,比较特殊的一种权限

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

-O
判断你是否是文件的拥有者
-G
文件的group-id是否与你的相同
-N
从文件上一次被读取到现在为止, 文件是否被修改过
f1 -nt f2
文件f1比文件f2新
f1 -ot f2
文件f1比文件f2旧
f1 -ef f2
文件f1和文件f2是相同文件的硬链接
!
"非" -- 反转上边所有测试的结果(如果没给出条件, 那么返回真).

这里只是先把一个实例贴在这里,暂且不做任何分析,因为现在去分析这个程序还有点为时尚早:

#!/bin/bash
#一个纯粹的shell脚本用来找出那些断掉的符号链接文件并且输出它们所指向的文件.
#以便于它们可以把输出提供给xargs来进行处理 :)
#比如. xxx.sh /somedir /someotherdir|xargs rm
#下边的方法, 不管怎么说, 都是一种更好的办法:
#find "somedir" -type l -print0|\
#xargs -r0 file|\
#grep "broken symbolic"|
#sed -e 's/^\|: *broken symbolic.*$/"/g'
#但这不是一个纯粹的bash脚本, 最起码现在不是.
#注意: 谨防在/proc文件系统和任何死循环链接中使用!

#如果没有参数被传递到脚本中, 那么就使用
#当前目录. 否则就是用传递进来的参数作为目录
#来搜索.
[ $# -eq 0 ] && directorys=`pwd` || directorys=$@

#编写函数linkchk用来检查传递进来的目录或文件是否是链接, 
#并判断这些文件或目录是否存在. 然后打印它们所指向的文件.
#如果传递进来的元素包含子目录, 
#那么把子目录也放到linkcheck函数中处理, 这样就达到了递归的目的.
linkchk () {
	for element in $1/*; do
	[ -h "$element" -a ! -e "$element" ] && echo \"$element\"
	[ -d "$element" ] && linkchk $element
	# 当然, '-h'用来测试符号链接, '-d'用来测试目录.
	done
}

#把每个传递到脚本的参数都送到linkchk函数中进行处理, 
#检查是否有可用目录. 如果没有, 那么就打印错误消息和
#使用信息.
for directory in $directorys; do
	if [ -d $directory ]
		then linkchk $directory
	else 
		echo "$directory is not a directory"
		echo "Usage: $0 dir1 dir2 ..."
	fi
done
exit 0

其他比较操作符
二元比较操作符用来比较两个变量或数字. 注意整数比较与字符串比较的区别.

整数比较

-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" ]
与=等价,不过,==比较操作符在双中括号对和单中括号对中的行为是不同的.我们看看实例,理解一下:

#!/bin/bash
a=abcdef
if [[ $a == ab* ]]
then
	echo "result1: true"
else
	echo "result1: false"
fi

if [[ $a == "ab*" ]]
then
	echo "result2: true"
else
	echo "result2: false"
fi

if [ $a == abcdef ]
then
	echo "result3: true"
else
	echo "result3: false"
fi

if [ $a == "ab*" ]
then
	echo "result4: true"
else
	echo "result4: false"
fi

if [ $a == ab* ]
then
	echo "result5: true"
else
	echo "result5: false"
fi
exit 0
结果:

root@ubuntu:~/resource/shell-study/0427-2013# ./test2
result1: true
result2: false
result3: true
result4: false
result5: false
分析:

1.只要前两个字符为“ab”就为true

2.意思是变量a只有是“ab*”这三个字符时跟后面比较的字符完全一致才为true

3.就是完全比配的情况,返回肯定是true

4.和第二个是一样的

5.这个就是比较特殊的情况,我的理解是在单【】中文字扩展匹配和单词分割有效,所以不能采用这么模糊比较的方法,模糊比较必须使用双【【】】

!=
不等号
if [ "$a" != "$b" ]
这个操作符将在[[ ... ]]结构中使用模式匹配.

<
小于, 按照ASCII字符进行排序
if [[ "$a" < "$b" ]]
if [ "$a" \< "$b" ]
注意"<"使用在[ ]结构中的时候需要被转义.

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

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

-n
字符串不为"null".当-n使用在中括号中进行条件测试的时候, 必须要把字符串用双引号引用起来. 如果采用了未引用的字符串来使用! -z, 甚至是在条件测试中括号中只使用未引用的字符串的话, 一般也是可以工作的, 然而, 这是一种不安全的习惯. 习惯于使用引用的测试字符串才是正路.
实例一

 #!/bin/bash
a=4
b=5
#  这里的"a"和"b"既可以被认为是整型也可被认为是字符串. 
#  这里在算术比较与字符串比较之间是容易让人产生混淆, 因为Bash变量并不是强类型的.
#  Bash允许对于变量进行整形操作与比较操作.但前提是变量中只能包含数字字符.
#  不管怎么样, 还是要小心. 
if [ "$a" -ne "$b" ]
then
	echo "$a is not equal to $b"
	echo "(arithmetic comparison)"
fi

if [ "$a" != "$b" ]
then
	echo "str($a) is not equal to str($b)."
	echo "(string comparison)"
	#     "4"  != "5"
	# ASCII 52 != ASCII 53
fi
exit 0
结果:

root@ubuntu:~/resource/shell-study/0427-2013# ./test3 
4 is not equal to 5
(arithmetic comparison)
str(4) is not equal to str(5).
(string comparison)
-ne比较的是两个整数,!=比较的是两个字符串

针对判断字符串是否为空,还是要特别说一下吧,比较特殊:

#!/bin/bash

# -n 
if [ -n $string1 ];then
	echo "String \"string1\" is not null."
else
	echo "String \"string1\" is null."
fi

#This is the best way
if [ -n "$string2" ];then
	echo "String \"string2\" is not null."
else
	echo "String \"string2\" is null."
fi

if [ $string3 ];then
	echo "String \"string3\" is not null."
else
	echo "String \"string3\" is null."
fi

string4=initialize
if [ $string4 ];then
	echo "String \"string4\" is not null."
else
	echo "String \"string4\" is null."
fi

string5="a = b"
if [ $string5 ];then
	echo "String \"string5\" is not null."
else
	echo "String \"string5\" is null."
fi

string6="a = b"
if [ "$string6" ];then
	echo "String \"string6\" is not null."
else
	echo "String \"string6\" is null."
fi

exit 0

结果:

root@ubuntu:~/resource/shell-study/0506-2013# ./test1.sh 
String "string1" is not null.
String "string2" is null.
String "string3" is null.
String "string4" is not null.
String "string5" is null.
String "string6" is not null.
分析:

string1和string2同是未定义的string,为什么string1判断是非null,而string2判断就是null,对string1的判断明显是错误的,对string的操作加上“”是很有必要的,sting5和string6的比较同样说明了这一点

继续看一个实例:

#!/bin/bash

NOARGS=65
NOTFOUND=66
NOTTXT=67

if [ $# -eq 0 ];then
	echo "Usage: `basename $0` no filename!" >&2
	exit $NOARGS
fi

FILENAME=$1

if [ ! -f "$FILENAME" ];then
	echo "File $FILENAME not found!" >&2
	exit $NOTFOUND
fi

if [ ${FILENAME##*.} != "txt" ];then
	echo "File $1 is not a txt file!" >&2
	exit $NOTTXT
fi

cat $1 | more
exit 0

上面几个判断条件使用方法是重点关注的地方:

1.判断参数个数为0退出

2.先判断FILENAME是否为文件,再取反,即不是文件或找不到文件退出

3.判断文件后缀名是不是“.txt”,不是则退出

结果:

root@ubuntu:~/resource/shell-study/0506-2013# ls
file.txt  file.zip  test1.sh  test2.sh
root@ubuntu:~/resource/shell-study/0506-2013# ./test2.sh 
Usage: test2.sh no filename!
root@ubuntu:~/resource/shell-study/0506-2013# ./test2.sh file
File file not found!
root@ubuntu:~/resource/shell-study/0506-2013# ./test2.sh file.zip 
File file.zip is not a txt file!
root@ubuntu:~/resource/shell-study/0506-2013# ./test2.sh file.txt 
total 7476
-rwxr-xr-x 1 root root  818232 2010-04-18 18:51 bash
-rwxr-xr-x 1 root root   30200 2010-02-08 02:54 bunzip2
-rwxr-xr-x 1 root root 1269432 2010-04-22 13:04 busybox
-rwxr-xr-x 1 root root   30200 2010-02-08 02:54 bzcat
lrwxrwxrwx 1 root root       6 2012-11-30 05:12 bzcmp -> bzdiff
-rwxr-xr-x 1 root root    2140 2010-02-08 02:54 bzdiff
lrwxrwxrwx 1 root root       6 2012-11-30 05:12 bzegrep -> bzgrep
-rwxr-xr-x 1 root root    4874 2010-02-08 02:54 bzexe
lrwxrwxrwx 1 root root       6 2012-11-30 05:12 bzfgrep -> bzgrep
-rwxr-xr-x 1 root root    3642 2010-02-08 02:54 bzgrep
-rwxr-xr-x 1 root root   30200 2010-02-08 02:54 bzip2
-rwxr-xr-x 1 root root    9580 2010-02-08 02:54 bzip2recover
lrwxrwxrwx 1 root root       6 2012-11-30 05:12 bzless -> bzmore
-rwxr-xr-x 1 root root    1297 2010-02-08 02:54 bzmore
-rwxr-xr-x 1 root root   50820 2010-03-04 19:29 cat
-rwxr-xr-x 1 root root   54956 2010-03-04 19:29 chgrp
-rwxr-xr-x 1 root root   50836 2010-03-04 19:29 chmod
-rwxr-xr-x 1 root root   54964 2010-03-04 19:29 chown
-rwxr-xr-x 1 root root    9632 2010-03-11 23:05 chvt
-rwxr-xr-x 1 root root   96140 2010-03-04 19:29 cp
-rwxr-xr-x 1 root root  114448 2010-03-04 19:25 cpio
-rwxr-xr-x 1 root root   83888 2010-04-01 12:22 dash
-rwxr-xr-x 1 root root   63128 2010-03-04 19:29 date
-rwxr-xr-x 1 root root    9672 2010-03-30 08:07 dbus-cleanup-sockets
-rwxr-xr-x 1 root root  292728 2010-03-30 08:07 dbus-daemon
-rwxr-xr-x 1 root root    5524 2010-03-30 08:07 dbus-uuidgen
-rwxr-xr-x 1 root root   54996 2010-03-04 19:29 dd
-rwxr-xr-x 1 root root   67316 2010-03-04 19:29 df
-rwxr-xr-x 1 root root  104528 2010-03-04 19:29 dir
-rwxr-xr-x 1 root root    5524 2010-03-22 10:51 dmesg
-rwxr-xr-x 1 root root   13824 2010-03-10 11:12 dnsdomainname
root@ubuntu:~/resource/shell-study/0506-2013# 

最后提一下逻辑判断方法

-a
逻辑与
exp1 -a exp2 如果表达式exp1和exp2都为真的话, 那么结果为真.

-o
逻辑或
exp1 -o exp2 如果表达式exp1和exp2中至少有一个为真的话, 那么结果为真.

这与Bash中的比较操作符&&和||非常相像, 但是这个两个操作符是用在双中括号结构中的.
比如用在【【】】中 [[ condition1 && condition2 ]]
-o和-a操作符一般都是和test命令或者是单中括号结构一起使用的, if [ "$exp1" -a "$exp2" ]

先到这里了,O(∩_∩)O~

我的专栏地址:http://blog.csdn.net/column/details/shell-daily-study.html

待续。。。。。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值