Lua:os.execute("sleep n")在无限循环中无法通过^C停止

在lua 5.2.4中,当在无限循环中使用广泛使用的os.execute('sleep n')方法时,程序无法通过^C(Ctrl-C)停止。

最小示例:

while true do
    print("HELLO!")
    os.execute("sleep 3")
end

我的问题是:

1.这是预期的行为吗?我本来以为程序在从os.execute命令返回后收到^C信号。

2.是否存在一种“内置”方法可以有效地进行睡眠?

点赞
用户107090
用户107090

Control-c 很可能被 os.execute 生成的 shell 捕获,而不是由 Lua 捕获。你需要查看 os.execute 返回的代码。当命令正常结束时,os.execute 返回 true,"exit",rc。否则,它返回 nil,etc。当 Control-c 中断它时,在我的机器上,它返回 nil,"signal",2

总之,试试这个代码:

while true do
    print("HELLO!")
    if not os.execute("sleep 3") then break end
end
2018-03-02 15:20:47
用户132382
用户132382

简短答案

您的 sleep 子进程被终端的 SIGINT 终止,但 os.execute 忽略了该信号,因此 lua 继续在其循环中。

更详细的答案

您的终端驱动程序将 Ctrl + C 转换为生成前台进程组的 SIGINT,其中包括(至少)您的 lua 进程和其子 sleep 进程。

(在 lua 脚本位于 os.execute 内部时,该信号极有可能被生成,因为您的脚本在大部分时间内都在其中。)

当发生这种情况时,sleep 进程立即被 SIGINT 终止。lua 进程在这种情况下忽略该信号。

它忽略 SIGINT,因为 os.execute 是传统库调用 system 的封装,如您可以在 源代码 中看到:

static int os_execute (lua_State *L) {
  const char *cmd = luaL_optstring(L, 1, NULL);
  int stat = system(cmd);      /* <<<<<<<<<<<<<<< here <<<<<<<<<<<<< */
  if (cmd != NULL)
    return luaL_execresult(L, stat);
  else {
    lua_pushboolean(L, stat);  /* true if there is a shell */
    return 1;
  }
}

该库调用具有非常特定的语义,包括在调用者中忽略 SIGINT。

2018-03-03 14:45:27