一、条件测试语法
1. read 接收输入
shell 变量除了直接赋值,也可脚本传参,read 接收输入。
-p 设置提示信息,-t 等待用户输入超时:
read -p "please input...." [接收用户输入的变量]
ubuntu@VM-0-9-ubuntu:~/shell$ read -t 15 -p "输入年龄 名字: " age usr_name
输入年龄 名字: 19 大壮
2. 四种条件测试写法
![表 6-1 条件测试常用的语法:test、[ ]、[[ ]]、(( )) 四种写法的说明](images/sh2-07.jpg)
其中 test 和中括号常用。
3. test 命令
test 评估表达式为真还是假,为真则状态码为 0,否则不为 0。
-e 判断文件是否存在(普通文件和目录),存在为真,否则为假。
布尔值中 0 为 false,执行状态中 0 就是成功的意思,二者不一样:
ubuntu@VM-0-9-ubuntu:~/shell$ test -e hello.py
# 查看状态码
ubuntu@VM-0-9-ubuntu:~/shell$ echo $?
1
# 不存在
ubuntu@VM-0-9-ubuntu:~/shell$ l
calcalation.sh calculation2.sh check_nginx_status.sh echo_test.sh* fail_houzhui.sh length_word.sh test.txt time.sh
ubuntu@VM-0-9-ubuntu:~/shell$ test calcalation.sh | xargs echo $?
0
test 语法
1.关于某个文件名的 【类型】 侦测(存在与否),如 test -e filename
-e 该『文件名』是否存在?(常用)
-f 该『文件名』是否为文件(file)?(常用)
-d 该『文件名』是否为目录(directory)?(常用)
-b 该『文件名』是否为一个 block device 装置?
-c 该『文件名』是否为一个 character device 装置?
-s 该『文件名』是否为一个 Socket 文件?
-p 该『文件名』是否为 FIFO (pipe) 文件?
-L 该『文件名』是否为一个连结档?
2. 关于文件的 【权限】 侦测,如 test -r filename
- r 侦测该文件名是否具有『可读』的属性?
- w 侦测该文件名是否具有『可写』的属性?
- x 侦测该文件名是否具有『可执行』的属性?
- u 侦测该文件名是否具有『SUID』的属性?
- g 侦测该文件名是否具有『SGID』的属性?
- k 侦测该文件名是否具有『Sticky bit』的属性?
- s 侦测该文件名是否为『非空白文件』?
3. 两个文件之间的比较,如:test file1 -nt file2
-nt (newer than) 判断 file1 是否比 file2 新
-ot (older than) 判断 file1 是否比 file2 旧
-ef 判断 file1 与 file2 是否为同一文件,可用在判断 hard link 的判定上。主要意义在判定,两个文件是否均指向同一个 inode 里!
4. 关于两个整数之间的判定,例如 test n1 -eq n2
-eq 两数值相等 (equal)
-ne 两数值不等 (not equal)
-gt n1 大于 n2 (greater than)
-lt n1 小于 n2 (less than)
-ge n1 大于等于 n2 (greater than or equal)
-le n1 小于等于 n2 (less than or equal)
5. 判定字符串的数据
test -z string 判定字符串是否为 0 ? 若 string 为空字符串,则为 true
test -n string 判定字符串是否非为 0 ? 若 string 为空字符串,则为 false。
注:-n 亦可省略
test str1 = str2 判定 str1 是否等于 str2 ,若相等,则回传 true
test str1 != str2 判定 str1 是否不等于 str2 ,若相等,则回传 false
6. 多重条件判定,例如:
test -r filename -a -x filename
-a (and) 两状况同时成立!例如 test -r file -a -x file,则 file 同时具有 r 与 x 权限时,才回传 true。
-o (or) 两状况任何一个成立!例如 test -r file -o -x file,则 file 具有 r 或 x 权限时,就可回传 true。
! 反相状态,如 test ! -x file,当 file 不具有 x 时,回传 true
二、test 的用法
1. && 和 ||
shell 对于真假判断的逻辑,提供 && 和 || 两个符号:
test 参数 测试对象 对结果判断的动作
# && 是左边成功(返回 0)才执行右边
# || 是左边失败(返回非 0)才执行右边
# cmd1 && cmd2 || cmd3 是顺序执行:
# cmd1 成功 → 执行 cmd2
# cmd1 失败 → 跳过 cmd2,直接执行 cmd3
# 与或非基本不写三个以上,为了保持可读性,三个以上不如if
ubuntu@VM-0-9-ubuntu:~$ l
nohup.out shell/ special.sh sub_str/
ubuntu@VM-0-9-ubuntu:~$ test -e special.sh && echo "文件存在"
文件存在
ubuntu@VM-0-9-ubuntu:~$ test -e speciallll.sh && echo "文件存在" || echo "文件不存在"
文件不存在
touch 有创建和修改文件时间的作用。
py 的脚本是自上而下执行,如果代码出错了,直接中断,但是 shell 的就会报错,然后接着继续执行:

上图的写法可以看到,即使没有创建成功,还是 echo 了。
如果执行出错了,可以限制后面不执行,用 test 即可。
ubuntu@VM-0-9-ubuntu:~$ test -e "hello" && echo "目录存在,不执行新建" || mkdir hello
目录存在,不执行新建
2. 判断文件
ubuntu@VM-0-9-ubuntu:~$ l
hello/ shell/ special.sh sub_str/
ubuntu@VM-0-9-ubuntu:~$ touch happy.txt
ubuntu@VM-0-9-ubuntu:~$ test -f happy.txt && echo "ok" || echo no
ok
# 对文件夹无用
ubuntu@VM-0-9-ubuntu:~$ test -f hello && echo "ok" || echo no
no
# -d 是判断文件夹的
ubuntu@VM-0-9-ubuntu:~$ test -d hello && echo ok || echo no
ok
3. 判断字符串
-z 空为真,-n 空为假。
ubuntu@VM-0-9-ubuntu:~$ test -z "" && echo ok || echo no
ok
# 空格也算字符
ubuntu@VM-0-9-ubuntu:~$ test -z " " && echo ok || echo no
no
ubuntu@VM-0-9-ubuntu:~$ test -n " " && echo ok || echo no
ok
ubuntu@VM-0-9-ubuntu:~$ test -n "" && echo ok || echo no
no
三、条件测试中括号详解
1. [ ] 的用法
为何需要中括号:很多脚本都需要 test 和中括号,可以去 /etc/init.d 查看,中括号的使用很重要,test 和中括号都很重要(两个功能几乎一样,[] 就是 test 的别名)。
中括号前后必须有空格。
条件测试使用变量必须添加双引号。
ubuntu@VM-0-9-ubuntu:~/shell$ [ -f "$file" ] && echo ok || echo no
ok
ubuntu@VM-0-9-ubuntu:~/shell$ [ -f "hello.py" ] && echo ok || echo no
no
与或非的逻辑适合在:如果成立,就执行,否则执行 的场景下使用的。
利用 -f 更严谨创建文件:
ubuntu@VM-0-9-ubuntu:~/shell$ [ -f "apple.png" ] && echo "存在" || touch apple.png
ubuntu@VM-0-9-ubuntu:~/shell$ [ -f "apple.png" ] && echo "存在" || touch apple.png
存在
2. 双中括号的使用(与 [] 几乎一样)
[[ ]] 支持 &&、||、=~ 正则匹配、< > 字符串比较,不需要对变量加双引号防空值。
[ ] 不支持这些,必须用 -a、-o 代替逻辑运算,变量必须加双引号。
日常写脚本用 [[ ]] 更安全方便,需要兼容 sh 时才用 [ ]。
[[ 表达式 ]]
验证文件是否有写入权限,root 无论有没有权限都可以操作,学习权限最好切换普通用户:
ubuntu@VM-0-9-ubuntu:~/shell$ touch terminal.txt
ubuntu@VM-0-9-ubuntu:~/shell$ chmod 0 terminal.txt
# 不可写权限
ubuntu@VM-0-9-ubuntu:~/shell$ ls -l terminal.txt
---------- 1 ubuntu ubuntu 0 Jul 23 18:04 terminal.txt
ubuntu@VM-0-9-ubuntu:~/shell$ cat terminal.txt
cat: terminal.txt: Permission denied
# 查看内容之前测试是否有 r (读)文件权限 -r作为参数写入
# 传入的文件名可以加引号,也可省略
ubuntu@VM-0-9-ubuntu:~/shell$ [[ -r "terminal.txt" ]] && cat terminal.txt || echo "无权查看"
无权查看
ubuntu@VM-0-9-ubuntu:~/shell$ chmod +r terminal.txt
ubuntu@VM-0-9-ubuntu:~/shell$ [[ -r "terminal.txt" ]] && cat terminal.txt || echo "无权查看"
# 此时没有内容,返回空
# 验证写权限 -w
ubuntu@VM-0-9-ubuntu:~/shell$ [[ -w terminal.txt ]] && (echo "内容省略喵" > terminal.txt) || echo "无权写入"
无权写入
ubuntu@VM-0-9-ubuntu:~/shell$ chmod +w terminal.txt
ubuntu@VM-0-9-ubuntu:~/shell$ [[ -w terminal.txt ]] && (echo "内容省略喵" > terminal.txt) || echo "无权写入"
ubuntu@VM-0-9-ubuntu:~/shell$ cat terminal.txt
内容省略喵
这一页的重点其实就三条:[] 前后必须有空格、变量必须加双引号、能用 [[ ]] 就别用 [], 剩下 -e -f -d -r -w -x -z -n 这些参数用的时候 man test 翻一眼就够。