TCL 脚本中断 "child killed: write on pipe with no readers"

TCL script breaks with "child killed: write on pipe with no readers"

升级到 Debian Jessie 后,我设置的 tcl motd 在登录时给我一个 st运行ge 错误 (主机名空白):

root     pts/0        XXXX-XX-XX-XXX-X Thu Jun 23 01:49:55 2016 - Thu Jun 23 01:                                                                     50:09 2016  (00:00)
child killed: write on pipe with no readers
    while executing
"exec -- last -F | head -n 2 | tail -n 1 "
    invoked from within
"set lastlog [exec -- last -F | head -n 2 | tail -n 1 ]"
    (file "/etc/motd.tcl" line 24)

我很困惑,因为 运行 我自己得到了打印在顶部的确切行,但是当 运行 作为脚本的一部分时它不应该打印任何东西,而是将其设置为变量的值,正如您从错误中引用的行中看到的那样:

set lastlog [exec -- last -F | head -n 2 | tail -n 1 ]

这里发生了什么导致神秘错误,我该如何解决?

错误是由一个以非零退出代码终止的子进程引起的(exec 对此非常敏感),而这又是由于尽管有管道,它仍然有输出要产生被关闭(使用 head 的常见问题)。最简单的解决方法是将 last -F 的整个输出读入 Tcl 并在那里截断行。幸运的是,这很容易:

set lastOutputLines [split [exec -- last -F] "\n"]
set lastlog [lindex $lastOutputLines 1]; # Zero-based indexing

只要 last 的输出不是很大,这就足够快了。

您可以使用子 shell 调用,其中 shell 不介意第一个命令通过信号终止,如:

set lastlog [exec -- bash -c "last -F | head -n 2 | tail -n 1"]

这样做的好处是可以在 "last" 发出其全部输出之前实际终止执行,如果输出很长,这很好。