C语言中每隔X秒执行命令的实现及相关技术问题问询
核心技术问题
- 使用
int ret = system("1"); if (WEXITSTATUS(ret) > 0) break;来检测错误的Shell命令(如system("1"))是否可行? - 能否使用
ctrl+c之外的其他快捷键来终止每隔X秒执行命令的任务?
引用自《Shell命令语言》:
2.8.2 命令的退出状态
每个命令都有一个退出状态,会影响其他Shell命令的行为。非工具类命令的退出状态在本节说明,标准工具的退出状态在各自章节说明。
若未找到命令,退出状态应为127;若找到命令名称,但该命令不是可执行工具,退出状态应为126。不通过Shell调用工具的应用应使用这些退出状态值报告类似错误。
若命令在单词展开或重定向期间失败,其退出状态应在1到125之间(包含边界值)。
在内部,为判断命令是否以非零状态退出,Shell应通过等效于wait()函数的WEXITSTATUS宏(定义于POSIX.1-2017的系统接口卷)获取的完整状态值来识别。当使用特殊参数'?'报告退出状态时,Shell应报告可用的全部8位退出状态。因接收信号而终止的命令,其退出状态应报告为大于128的值。
解答
1. 检测错误Shell命令的可行性
直接用if (WEXITSTATUS(ret) > 0) break;存在风险,必须先判断命令是否为正常退出(即未被信号终止),否则WEXITSTATUS的返回值是未定义的。
正确逻辑如下:
int ret = system("1"); if (WIFEXITED(ret)) { // 先确认是正常退出 int exit_status = WEXITSTATUS(ret); if (exit_status > 0) { // 非零状态表示命令执行失败 break; } }
结合《Shell命令语言》的规则:
- 命令未找到(如
system("1"))返回127 - 命令不可执行返回126
- 执行过程中出错返回1-125
这些场景的退出状态都是非零值,只要命令正常退出且状态非零就判定失败并退出循环,这个逻辑是可行的。但要注意,如果命令本身执行成功但故意返回非零(比如system("false")),也会触发退出,需根据实际需求判断是否需要包含这类情况。
2. 使用其他快捷键终止任务
可以实现,以下是两种可行方案:
方案一:监听ctrl+D(EOF)
ctrl+D是终端的EOF字符,默认情况下程序未读取标准输入时不会触发。可以在循环中加入非阻塞的标准输入检查:
#include <stdio.h> #include <stdlib.h> #include <stdbool.h> #include <sys/wait.h> #include <unistd.h> #include <fcntl.h> int main(void) { // 将标准输入设为非阻塞 int flags = fcntl(STDIN_FILENO, F_GETFL, 0); fcntl(STDIN_FILENO, F_SETFL, flags | O_NONBLOCK); while (true) { int ret = system("realpath uuid.c"); sleep(2); // 检查是否收到EOF(ctrl+D) char buf[1]; ssize_t read_bytes = read(STDIN_FILENO, buf, 1); if (read_bytes == 0) { // 读取到EOF break; } // 原有信号终止逻辑 if (WIFSIGNALED(ret) && (WTERMSIG(ret) == SIGINT || WTERMSIG(ret) == SIGQUIT)) break; } return 0; }
方案二:自定义ctrl+Q触发信号
ctrl+Q默认发送SIGCONT(恢复进程),可以通过修改终端控制字符,让它发送SIGQUIT信号,你的原有代码已处理该信号,直接生效:
在终端执行临时生效的命令:
stty quit ^Q
执行后按下ctrl+Q就会发送SIGQUIT,触发程序退出逻辑。
内容的提问来源于stack exchange,提问作者jian

