TypechoJoeTheme

MetMan's Blog

网站页面

Shell退出状态和test命令(一)

MetMan博 主
2024-01-11
/
0 评论
/
160 阅读
/
739 个字
/
百度已收录
01/11
本文最后更新于 2024年01月11日,已超过 252天没有更新。如果文章内容或图片资源失效,请留言反馈,我会及时处理,谢谢!

在介绍Shell的if与case前,应该先了解其Shell退出状态和test命令。因为if/case甚至循环while的条件是否成立是根据执行命令的退出状态来确定的。

退出状态

就像C语言函数调用必须要有返回值(除了void情况)一样,Shell执行完每一条命令后都会返回一个整数值作为退出状态(exit status)给调用它的程序。这里的Shell命令包括

  • 内置Shell命令
  • Shell函数
  • 外部命令

Shell约定整数值0表示命令执行成功,其它非0表示失败。

可以使用内置变量$?查询上一个命令退出状态。

$ ls test.F90
test.F90 
$ echo $?
0
$ echo foo
ls: cannot access 'foo': No such file or directory
$ echo $?   
2
$ echo $?   # 此时查询的是上一个echo命令的退出状态
0 

我们可以写一个简单的C程序,main函数返回值10,看程序退出状态是否和函数返回值相同。

// shell_exit_status.c
#include <stdio.h>

int main(){
    printf("calling shell_exit_status\n");
    return 10;
}
$ gcc -o shell_exit_status shell_exit_status.c
$ ./shell_exit_status 
calling shell_exit_status 
$  echo $?
10

不出所料,shell_exit_status程序命令执行退出状态与主函数返回值相同。因为像ls这些命令本质上就是C程序实现。

我们可以通过exit命令指定退出状态值给调用者。

$ exit 10 # 执行exit命令会立即退出脚本并将10作为退出状态返回给调用者

退出状态值不会超过255,因为只会返回低8位数值给父进程。

管道命令的退出状态

整个管道命令的退出状态反映的是管道中最后一个命令的退出状态。

可以使用参考资料中提到的例子进行验证。

!/bin/bash
echo "Hello World"
exit $1

以上脚本命名为hello_world.sh,其退出状态使用exit命令,具体退出值由脚本参数指定。

$ hello_world.sh 0
Hello World
$ echo $?
0
$hello_world.sh 5
Hello World
$ echo $?
5

使用管道进行测试:

$ hello_world.sh 5 | grep "Hello World"
Hello World
$ echo $?      # grep成功查找到该字符串
0
$ hello_world.sh 5 | grep "Hello World" | grep "Hello Universe"
$ echo $?     # 最后一个grep命令未能找到字符串
1

可以看出,管道退出状态实际上是管道中最后一个命令的退出状态。

如果想查询管道中每一个命令的退出状态,可以使用Bash内置环境变量PIPESTATUS查询,它是一个数组变量,包含管道每一条命令的退出状态,感兴趣可以进一步阅读参考资料内容。

命令的逻辑组合

多个命令的逻辑组合,可以使用shell运算符逻辑或(||)、且(&&)、非(!),其作用与C语言中逻辑运算符类似。

  • 逻辑非用法:退出状态取反
$ grep program test.F90  # grep查找成功
program demo
end program 
$ echo $? 
0
$ ! grep program test.F90 
program demo
end program 
$ echo $?
$ 1
  • 逻辑或用法:测试两种条件中是否有一个结果为真

短路(short-circuit)运算符,如果第一个条件为真,整个结果为真,没有必要判断第二个条件了,shell会停止对第二个条件的评估。

$ cd TMP || echo hello # 如果存在TMP目录,echo命令不会执行
$ echo $?
0
$ cd TMP1 || echo hello # 如果不存在TMP1目录,第二个条件echo会执行
-bash: cd: TMP1: No such file or directory
hello 
$ echo $?
0
$ cd TMP1 || ls abc.txt
-bash: cd: TMP1: No such file or directory
ls: cannot access 'abc.txt': No such file or directory 
$ echo $?
  • 逻辑且用法:测试两种条件是否都为真

短路(short-circuit)运算符,如果第一个条件为假,整个结果为假,没有必要判断第二个条件了,shell会停止对第二个条件的评估。

$ cd TMP1 && echo hello 
-bash: cd: TMP1: No such file or directory 
$ echo $?
1

参考资料

https://www.baeldung.com/linux/exit-status-piped-processes

shellbash
朗读
赞(0)
赞赏
感谢您的支持,我会继续努力哒!
版权属于:

MetMan's Blog

本文链接:

https://blog.metman.top/index.php/archives/82/(转载时请注明本文出处及文章链接)

评论 (0)

互动读者

标签云

最新回复

暂无回复

登录
X
用户名
密码