shell中大量的测试和比较选项而困惑呢?

这个技巧可以帮助您解密不同类型的文件、算术和字符串测试,这样您就能够知道什么时候使用 test、 [ ]、 [[ ]]、(( )) 或 if-then-else 了;

内置命令 test 根据表达式expr 求值的结果返回 0(真)或 1(假)。也可以使用方括号:test  expr和 [ expr ] 是等价的。 可以用 $? 检查返回值;可以使用 && 和 || 操作返回值;也可以用本技巧后面介绍的各种条件结构测试返回值。

清单 1. 一些简单测试

$? 显示命令返回值结果。0-为真,1-为假;

-d代表是否是目录

在清单 1 的第一个示例中,-gt 操作符对两个字符值之间执行算术比较。

在第二个示例中,用 [ ] 的形式比较两个字符串不相等。

在最后一个示例中,测试 HOME 变量的值,用单目操作符 -d 检查它是不是目录。

可以用 -eq、 -ne、-lt、 -le、 -gt 或 -ge 比较算术值,它们分别表示等于、不等于、小于、小于等于、大于、大于等于。

可以分别用操作符 =、 !=、< 和 > 比较字符串是否相等、不相等或者第一个字符串的排序在第二个字符串的前面或后面。

单目操作符 -z 测试 null 字符串,如果字符串非空 -n 返回 True(或者根本没有操作符)。

说明:shell 也用 < 和 > 操作符进行重定向,所以必须用 < 或 > 加以转义。清单 2 显示了字符串测试的更多示例。检查它们是否如您预期的一样。

清单 2. 一些字符串测试

表 1 显示了一些更常见的文件测试。如果被测试的文件存在,而且有指定的特征,则结果为 True。

表 1. 一些常见的文件测试
操作符 特征
-d 目录
-e 存在(也可以用 -a)
-f 普通文件
-h 符号连接(也可以用 -L)
-p 命名管道
-r 可读
-s 非空
-S 套接字
-w 可写
-N 从上次读取之后已经做过修改

除了上面的单目测试,还可以使用表 2 所示的双目操作符比较两个文件:

表 2. 测试一对文件
操作符 为 True 的情况
-nt 测试 file1 是否比 file2 更新。修改日期将用于这次和下次比较。
-ot 测试 file1 是否比 file2 旧。
-ef 测试 file1 是不是 file2 的硬链接。

其他一些测试可以用来测试文件许可之类的内容。请参阅 bash 手册获得更多细节或使用 help test 查看内置测试的简要信息。也可以用 help 命令了解其他内置命令。

-o 操作符允许测试利用 set -o  选项 设置的各种 shell 选项,如果设置了该选项,则返回 True (0),否则返回 False (1),如清单 3 所示。

清单 3. 测试 shell 选项
                
[ian@pinguino ~]$ set +o nounset
[ian@pinguino ~]$ [ -o nounset ];echo $?
1
[ian@pinguino ~]$ set -u
[ian@pinguino ~]$ test  -o nounset; echo $?
0

最后,-a 和 -o 选项允许使用逻辑运算符 AND 和 OR 将表达式组合在一起。单目操作符 ! 可以使测试的意义相反。可以用括号把表达式分组,覆盖默认的优先级。请记住 shell 通常要在子 shell 中运行括号中的表达式,所以需要用 ( 和 ) 转义括号,或者把这些操作符括在单引号或双引号内。清单 4 演示了摩根法则在表达式上的应用。

清单 4. 组合和分组测试

                
[ian@pinguino ~]$ test "a" != "$HOME" -a 3 -ge 4 ; echo $?
1
[ian@pinguino ~]$ [ ! ( "a" = "$HOME" -o 3 -lt 4 ) ]; echo $?
1
[ian@pinguino ~]$ [ ! ( "a" = "$HOME" -o '(' 3 -lt 4 ')' ")" ]; echo $?
1

(( 和 [[

test 命令非常强大,但是很难满足其转义需求以及字符串和算术比较之间的区别。幸运的是,bash 提供了其他两种测试方式,这两种方式对熟悉 C、C++ 或 Java? 语法的人来说会更自然些。

(( )) 复合命令 计算算术表达式,如果表达式求值为 0,则设置退出状态为 1;如果求值为非 0 值,则设置为 0。不需要对 (( 和 )) 之间的操作符转义。算术只对整数进行。除 0 会产生错误,但不会产生溢出。可以执行 C 语言中常见的算术、逻辑和位操作。 let 命令也能执行一个或多个算术表达式。它通常用来为算术变量分配值。

清单 5. 分配和测试算术表达式

                
[ian@pinguino ~]$ let x=2 y=2**3 z=y*3;echo $? $x $y $z
0 2 8 24
[ian@pinguino ~]$ (( w=(y/x) + ( (~ ++x) & 0x0f ) )); echo $? $x $y $w
0 3 8 16
[ian@pinguino ~]$ (( w=(y/x) + ( (~ ++x) & 0x0f ) )); echo $? $x $y $w
0 4 8 13

同使用 (( )) 一样,利用复合命令 [[ ]] 可以对文件名和字符串使用更自然的语法。可以用括号和逻辑操作符把 test 命令支持的测试组合起来。

清单 6. 使用 [[ 复合命令

                
[ian@pinguino ~]$ [[ ( -d "$HOME" ) && ( -w "$HOME" ) ]] &&  
>  echo "home is a writable directory"
home is a writable directory

在使用 = 或 != 操作符时,复合命令 [[ 还能在字符串上进行模式匹配。匹配的方式就像清单 7 所示的通配符匹配。

清单 7. 用 [[ 进行通配符测试

                
[ian@pinguino ~]$ [[ "abc def .d,x--" == a[abc]* ?d* ]]; echo $?
0
[ian@pinguino ~]$ [[ "abc def c" == a[abc]* ?d* ]]; echo $?
1
[ian@pinguino ~]$ [[ "abc def d,x" == a[abc]* ?d* ]]; echo $?
1

甚至还可以在 [[ 复合命令内执行算术测试,但是千万要小心。除非在 (( 复合命令内,否则 < 和 > 操作符会把操作数当成字符串比较并在当前排序序列中测试它们的顺序。清单 8 用一些示例演示了这一点。

清单 8. 用 [[ 包含算术测试

                
[ian@pinguino ~]$ [[ "abc def d,x" == a[abc]* ?d* || (( 3 > 2 )) ]]; echo $?
0
[ian@pinguino ~]$ [[ "abc def d,x" == a[abc]* ?d* || 3 -gt 2 ]]; echo $?
0
[ian@pinguino ~]$ [[ "abc def d,x" == a[abc]* ?d* || 3 > 2 ]]; echo $?
0
[ian@pinguino ~]$ [[ "abc def d,x" == a[abc]* ?d* || a > 2 ]]; echo $?
0
[ian@pinguino ~]$ [[ "abc def d,x" == a[abc]* ?d* || a -gt 2 ]]; echo $?
-bash: a: unbound variable

条件测试

虽然使用以上的测试和 &&、 || 控制操作符能实现许多编程,但 bash 还包含了更熟悉的 “if, then, else” 和 case 结构。学习完这些之后,将学习循环结构,这样您的工具箱将真正得到扩展。

If、then、else 语句

bash 的 if 命令是个复合命令,它测试一个测试或命令($?)的返回值,并根据返回值为 True(0)或 False(不为 0)进行分支。虽然上面的测试只返回 0 或 1 值,但命令可能返回其他值。

bash脚本编程之二 字符串测试及for循环的更多相关文章

  1. 高级Bash脚本编程(二)

    高级Bash脚本编程(二) 退出 退出状态码 退出:exit 被用来结束一个脚本,它也返回一个值,并且这个值会传递给脚本的父进程,父进程会使用这个值做下一步的处理. 每个命令都会返回一个退出状态码,成 ...

  2. bash脚本编程之二 条件判断and 逻辑运算

    1.条件测试结构 1) if/then结构: 判断命令列表的退出码是否为0,0为成功. 如果if和then在条件判断的同一行上的话, 必须使用分号来结束if表达式: if和then都是关键字. 关键字 ...

  3. 5-3 bash脚本编程之二 条件判断

    1. 条件测试的表达式 1. [ expression ]  :注意这个中括号的前后都有一个空格 2. [[ expression ]] 3. test expression 2.条件判断的类型 1. ...

  4. Bash脚本编程之字符串处理

    简介 其实这里说得字符串处理,对应的是bash官网中的[Shell Parameter Expansion],不过直接去看这部分内容实在是太难以理解了.就按照马哥所说的字符串处理会比较好理解,平常使用 ...

  5. Bash脚本编程总结

    bash脚本编程之用户交互: read [option]… [name …]  -p ‘PROMPT’  -t TIMEOUT bash -n /path/to/some_script  检测脚本中的 ...

  6. Bash脚本编程之数组

    数组简介 在bash脚本编程当中,变量是存储单个元素的内存空间:而数组是存储多个元素的一段连续的内存空间. 数组由数组名和下标构成,如下. ARRAY_NAME[SUBSCRIPT] 数组按照下标的类 ...

  7. 高级bash脚本编程(三)

    高级bash脚本编程 知识点 compound 和 comparison -a 逻辑与 exp1 -a exp2 如果表达式 exp1 和 exp2 都为真的话,那么结果为真. -o 逻辑或 exp1 ...

  8. bash脚本编程知识储备

    bash脚本编程:     脚本程序:解释器解释执行: 首先得理清一些琐碎的知识点,我尽量把我所学的帮朋友一起梳理一下 编程环境:(我会在接下来的篇章,图文例子三结合的方式带大家一起学习)       ...

  9. Bash脚本编程之算术运算

    简介 Bash所支持的算术运算和C语言是一样的,这里指的是操作符(operator)以及它们的优先级(precedence).结合性(associativity)和值,详见Shell Arithmet ...

随机推荐

  1. ipvsadm命令使用方法

    由于LVS(IPVS)是工作在内核空间的,因此要在用户空间对其进行配置和管理就要用到ipvsadm,ipvsadm是LVS在用户空间的管理命令. 一般在安装linux(CentOS6.5)时该命令是为 ...

  2. 《统计推断(Statistical Inference)》读书笔记——第3章 统计分布族

    在科学研究中最重要的两种思维范式是“简化”和“还原”,所谓“简化”是指人依据不太复杂的,可理解的规律认识世界:所谓“还原”是指任何复杂的现象归根结底可以由若干简单的机制解释.各种统计分布族就是统计学中 ...

  3. 怎样用JS获取ASP.NET服务器控件的客户端ID

    虽然简单,不过曾经困扰多时,还是记录一下吧. 来源:http://mou518.blog.163.com/blog/static/1756052222010111434428828/ 因为经常服务器控 ...

  4. Python copy and deepcopy

    Python中的对象之间赋值时是按引用传递的,如果需要拷贝对象,需要使用标准库中的copy模块. 1. copy.copy 浅拷贝 只拷贝父对象,不会拷贝对象的内部的子对象. 2. copy.deep ...

  5. 读文档readarx.chm

    readarx.chm <Tips and Techniques> Incremented AutoCAD Registry Number Ideally, a change of reg ...

  6. IntelliJ IDEA 环境配置

    0. 下载 jdk 用于 java developer kit  下载地址 见 rj.baidu.com 1. 从百度 网盘下载 ideaIU-2016.2.5.exe 并安装在window上 2. ...

  7. 在浏览器中输入Google.com并且按下回车之后发生了什么(转载)

    原文地址:https://github.com/skyline75489/what-happens-when-zh_CN#id9 本文试图回答一个古老的面试问题:当你在浏览器中输入google.com ...

  8. nodejs-express 报错View is not a constructor

    可能是express版本问题 view修改为views – app.set('views',__dirname + '/views');

  9. mysql数据库优化小结

    一.常见数据库的优化操作 1.表的设计要符合三范式. 2.添加适当的索引,索引对查询速度影响很大,必须添加索引.主键索引,唯一索引,普通索引,全文索引 3.添加适当存储过程,触发器,事务等. 4.读写 ...

  10. js 正则

    /判断输入内容是否为空    function IsNull(){        var str = document.getElementById('str').value.trim();      ...