当前位置: 首页 > Linux

bash中的退出状态机制

时间:2023-04-07 00:49:46 Linux

程序的退出状态当一个程序结束时,它会向父进程报告自己的退出状态(exitstatus)。通过向库函数exit或系统调用_exit传递一个int类型的变量,获取当前程序的退出状态。在Linux中,WEXITSTATUS返回的退出状态取值范围是[0,255]之间的整数。如果传递的值不在这个范围内,内核会自动帮你强制为u_int8_t。通过waitpid库函数可以获取子进程的退出状态,其值保存在参数wstatus的低8位。//在wait.h中定义#defineWEXITSTATUS(status)__WEXITSTATUS(status)//定义在waitstatus.h/*如果是WIFEXITED(STATUS),状态的低8位。*/#define__WEXITSTATUS(status)(((status)&0xff00)>>8)下面的例子展示了如何使用waitpid和相关的宏函数来获取子进程的退出状态:#include#include#include#include#include#definePARENT_EXIT10086#defineCHILD_EXIT-10intmain(){pid_tpid=fork();如果(pid>0){intwstatus;//父进程等待子进程完成,使用WUNTRACED选项跟踪完成的子进程pid_tchild_pid=waitpid(pid,&wstatus,WUNTRACED);if(WIFEXITED(wstatus))printf("孩子退出状态:%d\n",WEXITSTATUS(wstatus));elseperror("Badwaitstatus\n");//父进程退出exit(PARENT_EXIT);}elseif(pid==0){//子进程立即退出,所以需要父进程设置WUNTRACEDexit(CHILD_EXIT);}else{//处理错误perror("fork\n");exit(EXIT_FAILURE);}}编译运行上面的例子得到强制状态码,我们使用WIFEXITED判断等待的子进程是否执行成功,然后通过WEXITSTATUS获取成功子进程的退出状态,对于程序来说,最终的退出状态就是主进程的退出状态>gccecitcode.c;。/a.out;echo"Parentexitstatus:$?"Childexitstatus:246#-10Forcedtouint8Parentexitstatus:102#10086Forcedtouint8在POSIX标准中,退出状态0表示程序正常退出,1表示发生错误,其他数字由程序自己指定,所以在glibc的stdlib.h中只定义了如下宏:#defineEXIT_FAILURE1/*Failingexitstatus。*/#defineEXIT_SUCCESS0/*成功退出状态。*/program一般每个退出状态所代表的退出原因(终止)都会事先在文档中约定好,比如在ls的帮助文档中:>ls--help...othercontent...Exitstatus:#exitstatus0ifOK,#Normalexecution1ifminorproblems#小问题,eg:cannotaccesssubdirectories2ifserioustrouble#严重错误,如:无法访问命令行参数...其他内容...bash中的commandexitstatus会记录执行命令的退出状态,可以用$?获取最近执行的命令的退出状态。bash本身的退出状态就是最后执行的命令的退出状态,相当于显式指定exit$?。如果不执行任何命令就退出,bash的退出状态为0。注意bash中0表示true,非0表示false。#使用exit显式指定退出状态>bash>exit98exit>echo$?98#什么都不执行,退出状态为0>bashexit#Ctrl+D退出>echo$?0#默认为最后一个命令的退出状态>bash>ecasdecasd:commandnotfoundexit#Ctrl+D退出>echo$?127bash中对不同类型命令的退出状态的规定如下:内置命令:由于内置命令不需要启动额外的Subprocess,所以需要用返回值来模拟退出状态。每个函数都定义了自己的退出状态,例如:内置命令源使用脚本文件中最后一条命令的返回状态作为命令的返回状态。bash中的所有内置命令都使用退出状态2来指示使用错误,例如:错误的选项,缺少参数。>cd-+-#错误的参数bash:cd:-+:invalidoptioncd:usage:cd[-L|[-P[-e]][-@]][dir]>echo$?2外部命令:外部命令的退出状态是使用waitpid得到的子进程的退出状态。如果子进程在执行过程中被编号为N的信号终止,则退出状态为128+N。shell函数:定义shell函数时,如果函数名与之前定义的只读函数名相同,则退出状态为1。当出现语法错误时,退出状态为2。执行shell函数时,函数中执行的最后一条命令的退出状态就是整个函数的退出状态。#二次定义只读函数错误>func(){echo;}>readonly-ffunc>func;回声$?0>;func(){echo点;}bash:func:readonlyfunction>echo$?1#定义函数时出现语法错误>fune(){aa}bash:syntaxerrornearunexpectedtoken'{aa}'>echo$?2#的退出状态该函数是最后执行的命令的退出状态>funr(){echo;返回6;}>乐趣;回声$?#echo6打印的空行#return6是函数中最后执行的命令Expression:用((...))或let修饰的表达式的退出状态取决于表达式的值。如果表达式的值为0,则退出状态为1;如果表达式的值不为零,则退出状态为0.>let0+0;echo$?1#表达式值为零>((7-5));echo$?0#表达式值为非零commandlist:use;,&,&&,||命令称为命令列表,其中命令与&&和||连接使用左结合性(leftassociativity)模式来执行列表中的命令。整个命令列表的退出状态就是最后一个命令的退出状态。另外,$(LISTS)和进程控制结构如:for,while等的返回状态也是该结构中命令列表的退出状态。#功能:如果能ping通baidu.com,输出`baidu.comisup`,否则输出`baidu.comisdown`>ping-c1baidu.com&>/dev/null&&echo'baidu.com已启动'||echo'baidu.comisdown'baidu.comisdown>echo$?0#是否能ping通,命令列表的退出状态等同于上一条命令的退出状态。左结合模式广泛应用于各种语言的逻辑运算符优化。对于逻辑与运算符&&,以eq1&&eq2为例,只有两边都为True。会返回True,所以当eq1为False时,eq2不会执行;对于逻辑或运算符||,取eq1||以eq2为例,只要两边都有True,就会返回True,所以当eq1为True时,eq2不会执行。脚本:使用.orsource运行一个脚本文件相当于在当前bash中执行一个代码块,脚本中最后执行的命令的退出状态就是脚本的退出状态。使用./script名或bash脚本名执行一个脚本文件相当于执行一个外部命令,脚本的退出状态就是外部命令bash的退出状态。如果脚本中执行的最后一个命令是exit,则使用.或source执行脚本文件,执行完成后退出当前bash。后台作业和协作进程:使用不带选项的等待命令来获取最后完成的后台作业的退出状态。如果使用wait-n,可以得到指定后台作业的退出状态。如果job不存在,则退出状态为127。使用coprocinsubshell中执行的命令的退出状态,可以像后台作业一样通过wait获取,coproc本身的退出状态一直为0。>{sleep10;一个;}&[1]558>wait-n1[1]+退出127{睡眠10;一个;}>coproc{睡眠10;一个;}[1]558>echo$?0#这是coproc的执行结果>jobs[1]+Exit127coprocCOPROC{sleep10;一个;管道命令:默认情况下,管道的退出状态取决于管道中最后一个命令的退出状态。如果设置了set-opipefail,那么只有当管道中所有命令的退出状态都为0时,整个管道的退出状态才为0,否则为最后一个非零退出状态。添加!管道前的符号可以反转整个管道的退出状态。bash中的特殊变量$PIPESTATUS以数组的形式存储了最近一次执行的前台管道的退出状态,需要注意的是个别命令也会被记录,即${PIPESTATUS[0]}和$?是等价的。#管道的退出状态为最后一条命令的退出状态>ps|xxp2>/dev/null|猫;echo$?0>设置-opipefail>附注|xxp2>/dev/null|猫;echo$?127#setpipefailsogetthelastnon-zeroexitstatus#管道中每个命令的退出状态按顺序记录在数组中>easd2>/dev/null|ls/nou2>/dev/null|more2>/dev/null>echo${PIPESTATUS[@]}12720#还记录了一条没有管道符号的命令>pingasbasdasd2>/dev/null;echo${PIPESTATUS[0]}2>pingasbasdasd2>/dev/null;echo$?2Reference退出状态范围Bash手册页