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

2023-12-10

最近我开始对我的 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

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

这是我的问题。如何检测 shell 是否无法执行命令?实际上,失败可能是出于任何原因,但要点是脚本没有启动。


关于何时使用的一般评论errno

没有设置标准 C 或 POSIX 库函数errno为零。根据以下内容打印错误消息errno when fd不为NULL是不合适的;错误编号不是来自popen()(或者没有设置,因为popen()失败的)。印刷res after pclose()还可以;添加strerror(errno)遇到同样的问题(信息errno可能完全无关)。您可以设置errno在调用函数之前清零。如果该函数返回失败指示,则可能需要查看errno(查看函数的规范——它是否被定义为设置errno失败?)。然而,errno即使成功,也可以通过函数设置为非零。用于设置 Solaris 标准 I/Oerrno = ENOTTY如果输出流未连接到终端,即使操作成功;也许现在仍然如此。和 Solaris 设置errno即使成功也是完全合法的;看看才是合法的errno如果 (1) 该功能报告故障并且 (2) 该功能被记录为设置errno(通过 POSIX 或系统手册)。

See C11 §7.5 错误<errno.h> ¶3:

The value of errno in the initial thread is zero at program startup (the initial value of errno in other threads is an indeterminate value), but is never set to zero by any library function.202) The value of errno may be set to nonzero by a library function call whether or not there is an error, provided the use of errno is not documented in the description of the function in this International Standard.

202) Thus, a program that uses errno for error checking should set it to zero before a library function call, then inspect it before a subsequent library function call. Of course, a library function can save the value of errno on entry and then set it to zero, as long as the original value is restored if errno's value is still zero just before the return.

POSIX 类似(errno):

许多函数都提供错误号errno,其类型为int并定义在<errno.h>。的价值errno仅应在调用明确声明要设置的函数之后定义,直到下一个函数调用更改它或应用程序为其分配值为止。的价值errno仅当函数的返回值表明它有效时才应检查它。应用程序应获得以下定义errno通过包含<errno.h>。 POSIX.1-2017 本卷中的函数不得将 errno 设置为 0。errno成功调用函数后未指定,除非该函数的描述指定errno不得修改。

popen() and pclose()

POSIX 规范popen()并不是很有帮助。只有一种情况可以popen()'必须失败';其他一切都是“可能会失败”。

然而,详细信息为pclose()更有帮助,包括:

如果命令语言解释器无法执行,则返回子终止状态pclose()应如同命令语言解释器终止使用exit(127) or _exit(127).

and

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

这意味着pclose()返回它收到的值waitpid()— 调用的命令的退出状态。注意,必须使用waitpid()(或同等的选择性功能——寻找wait3() and wait4()在 BSD 系统上);它无权等待除由创建的子进程之外的任何其他子进程popen()对于这个文件流。有关于的处方pclose()必须确保子进程已退出,即使某些其他函数在此期间等待已死亡的子进程,从而导致系统丢失由popen().

如果将十进制 32512 解释为十六进制,则会得到 0x7F00。如果你使用了WIFEXITED and WEXITSTATUS宏来自<sys/wait.h>就这样,你会发现退出状态是127(因为0x7F is 127十进制,退出状态编码在返回状态的高位中waitpid().

int res = pclose(fd);

if (WIFEXITED(res))
    printf("Command exited with status %d (0x%.4X)\n", WEXITSTATUS(res), res);
else if (WIFSIGNALED(res))
    printf("Command exited from signal %d (0x%.4X)\n", WTERMSIG(res), res);
else
    printf("Command exited with unrecognized status 0x%.4X\n", res);

请记住0是表示成功的退出状态;其他任何内容通常都表明存在某种错误。您可以进一步分析退出状态来查找127或中继信号等。您不太可能获得“已发出信号”状态或无法识别的状态。

popen()告诉你孩子失败了。

当然,有可能执行的命令实际上以状态 127 退出;这不可避免地会造成混乱,唯一的解决方法是避免退出状态在 126 到 128 +“最大信号数”范围内(如果有 63 个已识别信号,则可能意味着 126 .. 191)。价值126POSIX 也使用它来报告 shebang 中指定的解释器(#!/usr/bin/interpreter) 丢失(与要执行的程序不可用相反)。是否返回pclose()是一个单独的讨论。信号报告是由 shell 完成的,因为否则没有(简单)方法来报告孩子因信号而死亡。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

如何检测 shell 在 popen 调用后是否无法执行命令?不要与命令退出状态混淆 的相关文章

随机推荐

  • 在 Node.js 中复制 Java 密码哈希代码 (PBKDF2WithHmacSHA1)

    编辑 我的问题已更新 请查看这篇文章的底部以了解最新一期 我把剩下的留给那些想阅读整个故事的人 我一直致力于将一个小型 Java 应用程序转换为 Node js 大部分进展顺利 我必须查找大量 Java 函数来弄清楚它们的作用以及如何在 N
  • 获取mysql查询中一行的排名

    我使用此查询根据每个名字获得的票数为他们分配排名 但它返回错误 1248 每个派生表必须有自己的别名 这是我的代码 SELECT rownum rownum 1 AS rank name vote FROM table SELECT row
  • getJSON 不支持 async:false

    我下面有这段代码 它应该返回调用的结果 我需要同步执行此操作 以便我知道一切都很好 但它似乎不起作用 我究竟做错了什么 jQuery library http code jquery com jquery 1 9 1 min js func
  • Apache Beam -> BigQuery - 用于重复数据删除的 insertId 不起作用

    我使用 apache beam 和 google dataflow runner 将数据从 kafka 流式传输到 BigQuery 我想利用 insertId 进行重复数据删除 我在谷歌文档中找到了描述 但即使插入是在几秒钟之内发生的 我
  • 如何在 Google 地图中跟踪用户全天的位置?

    您如何跟踪用户一整天的位置 就像 Google 地图中的时间线一样 我有两个想法 例如 如果我有 200LatLng每天的价值 我如何通过所有这些LatLng值到谷歌地图作为点 我得到了一个谷歌文档参考因为我最多只能跟踪 10 个位置点 是
  • 如何在平板电脑/智能手机上启用立体声录音,尽管有两个内置麦克风,但仅产生单声道?

    到目前为止 我认为这是一个固件错误 但现在我刚刚发现第二个设备 它有两个内部麦克风胶囊 但只产生单声道信号 第一个是S2加GT I9105PAndroid 4 1 2 和现在HTC One M7 the Nexus 10Android 4
  • 使用servlet接收音频文件

    故事简介 我有一个 Servlet 它接收一个我无法读取的请求 getContentType audio x wav 我需要读取这一波并将其保存在服务器端 详细故事 我对 Flex javascript PHP 和 Python 一无所知
  • 重命名 s3 中的 Pyspark 输出文件

    我使用以下命令将 pyspark 数据帧保存到 s3 df coalesce 1 write partitionBy DATE format com databricks spark csv mode overwrite option he
  • 使用 glm 和二项式族更改参考组

    当我在 R 中使用由三个级别 较高 中 和 较低 组成的独立因子变量运行二项式回归时 我想使用以下命令更改参考类别relevel我收到此错误 Error in relevel ordered cbsnivcat3 Lower relevel
  • 删除括号前后的所有空格

    我想删除一个或多个空格before and after任何括号 下列的这个帖子PHP 的问题已通过以下正则表达式解决 lt 现在我想做同样的事情JavaScript但 Javascript 正则表达式引擎不具有与 PHP 相同的前瞻和后瞻功
  • 如何在 Android Lollipop 中保存 WebView 状态并恢复它?

    这个问题被问过多次 并且有曾经有效的答案 最近在文档中表示 出于安全原因 他们删除了此功能 webView状态只能恢复一些有限的东西 我尝试了多种方法来做到这一点 但每次刷新 webView 状态时 它都不会显示 webView 内容 我想
  • 如何使用 VSTS 扩展隐藏快速添加面板待办事项项?

    我想制作一个 VSTS 扩展 可以在加载页面时隐藏快速添加面板积压项目 快速添加面板待办事项 该扩展是针对 TFS 2015 更新 2 进行的 我已经运行了这段代码 但没有任何反应 动作 html
  • 在python beautifulsoup中从html中提取json

    我正在做一些爬虫 需要从用 bs4 做汤后返回的 div 中提取 json 内容 所以我现在得到了一个变量字符串 其中包含此文本变量 div class header product js header product div
  • 在 Polly 重试策略中重用 HttpRequestMessage

    An HttpRequestMessage对象只能使用一次 未来尝试使用同一对象会抛出异常 我正在使用 Polly 重试一些请求 但遇到了这个问题 我知道如何克隆请求 有很多关于 SO 的示例 但我不知道如何克隆请求并在 Polly 重试时
  • 无法从 recyclerview 实时数据库中删除项目

    我正在尝试设置一种方法来从 firebase 实时数据库中永久删除项目 由于某种原因 我不断收到一条错误消息 提示 getRef 不存在 尽管很多人使用相同的方法来删除项目 但我已尝试阅读并尝试多篇文章中的解决方案 但它并没有真正起作用 这
  • 如何在QML中封装自定义控件?

    我想创建一个 QML 自定义控件库 并将其提供给我的客户 同时 我不希望我的客户通过查看 QML 源代码来 逆向工程 我的控件 避免这种情况的最佳选择是什么 理想的情况是我将控件作为编译库提供 他们可以将其导入到自己的项目中 我的目标平台是
  • 如何在 3 延迟后删除元素?

    gallerie ul li eq 1 animate opacity 1 1250 remove results in instand remove gallerie ul li eq 1 delay 3000 remove instan
  • std::ignore 与结构化绑定?

    Prelude std tuple
  • 如何将 javascript 变量包装在 span 或粗体标签中?

    我得到了一些 JavaScript 可以创建一个数字时钟来访问网页 这工作得很好 但是我正在尝试修改它 将 am pm 后缀 或此代码中的 diem 包装在 span 或粗体标签中 以便我可以在 CSS 中对其进行不同的样式设置 我确信这对
  • 如何检测 shell 在 popen 调用后是否无法执行命令?不要与命令退出状态混淆

    最近我开始对我的 python 脚本进行一些测试 由于某些尴尬的原因 运行 python 脚本并检查其输出的模块是用 C 编写的 并添加了一些其他语言 这种方式目前对于我来说使用起来比较方便 单个测试使用以下代码运行 FILE fd NUL