[如何检测popen调用后shell是否无法执行命令?不要与命令退出状态混淆

问题描述 投票:0回答:1

最近,我开始对python脚本进行一些测试。出于某种尴尬的原因,运行python脚本并检查其输出的模块以C语言编写,并添加了其他一些语言。这种方式现在对我来说更方便。

单个测试使用以下代码运行:

 FILE *fd = NULL;

 fd = popen("cmd", "r");
 if(NULL == fd){
  fprintf(stderr, "popen: failed\n");
  return 1;
 }
 fprintf(stderr, "res = %d: %s\n", errno, strerror(errno));

 int res = pclose(fd);
 fprintf(stderr, "res = %d: %s\n", res, strerror(errno));

如您从上面看到的,代码仅在popen的帮助下运行脚本并检查其退出状态。但是有一天,我遇到了popen被给出错误论点的情况。这样的事情发生了:

fd = popen("python@$#!", "r");

测试模块已返回:

res = 0: Success
sh: 1: python@0!: not found
res = 32512: Success

因此,popen会因上述错误而愉快地运行。并且只有pclose返回了一些退出状态。 errno为zero。在所有这些之间,shell也输出了它。

这是我的问题。如何检测Shell是否无法执行命令?该失败实际上可能是由于任何原因,但要点是该脚本不会事件启动。

c linux shell popen
1个回答
0
投票

一般评论

没有标准C或POSIX库函数将errno设置为零。当errno不为NULL时,基于fd打印错误消息是不合适的。错误号不是来自popen()(或因为popen()失败而未设置)。 res确定后打印pclose();添加strerror(errno)会遇到相同的问题(errno中的信息可能完全不相关)。您可以在调用函数之前将errno设置为零。如果函数返回故障指示,则可能需要查看errno(查看函数的规格-是否定义为在故障时设置errno?)。但是,即使成功,也可以通过函数将errno设置为非零。即使操作成功,如果输出流未连接到终端,Solaris标准I / O仍将设置errno = ENOTTY。它可能仍然可以

[popen()pclose()

popen()的POSIX规范没有很大帮助。在仅一种情况下,popen()“必须失败”;其他一切都是“可能失败”。

但是,popen()的详细信息更为有用,包括:

如果无法执行命令语言解释器,则pclose()返回的子终止状态应类似于使用pclose()pclose()终止的命令语言解释器。

成功返回后,exit(127)应返回命令语言解释器的终止状态。否则,_exit(127)应返回-1并设置errno以指示错误。

如果将十进制32512解释为十六进制,则会得到0x7F00。并且,如果您使用pclose()中的pclose()WIFEXITED宏,则会发现退出状态为WEXITSTATUS(因为<sys/wait.h>为十进制127,并且退出状态编码为0x7F返回的状态的高阶位。

[127告诉你孩子失败了。

当然,执行的命令实际上可能以状态127退出自身;这不可避免地会造成混淆,解决该问题的唯一方法是避免退出状态在126至128 +“最大信号数”范围内(如果有63个已识别的信号,则可能意味着126..191)。 POSIX还使用值waitpid()来报告在shebang中指定的解释器(popen())丢失的情况(与要执行的程序不可用相反)。是否由126返回是一个单独的讨论。而且信号报告由外壳程序完成,因为没有(简便)方法可以报告孩子因信号而死亡。

© www.soinside.com 2019 - 2024. All rights reserved.