TCL脚本打破了“杀了孩子:没有读者写在管道上”

时间:2016-06-24 19:07:57

标签: bash debian tcl

升级到Debian Jessie之后,我设置的tcl motd在登录(主机名消隐)时给了我一个奇怪的错误:

var products = [("Kayak","A boat for one person","Watersports",275.0,10),
                ("Lifejacket","Protective and fashionable","Watersports",48.95,14),
                ("Soccer Ball","FIFA-approved size and weight","Soccer",19.5,32),
                ("Corner Flags","Give your playing field a professional touch","Soccer",34.95,1),
                ("Stadium","Flat-packed 35,000-seat stadium","Soccer",79500.0,4),
                ("Improve your brain efficiency by 75%","Chess",16.0,8),
                ("Unsteady Chair","Secretly give your opponent a disadvantage","Chess",29.95,3),
                ("Human Chess Board","A fun game for the family","Chess",75.0,2),
                ("Bling-Bling King","Gold-plated,diamon-studded King","Chess",1200.0,4)]

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

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)

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

2 个答案:

答案 0 :(得分:3)

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

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

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

答案 1 :(得分:1)

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

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

这具有实际终止" last"的执行的优点。在它发出整个输出之前,如果输出很长就很好。