使用Tcl expect获取命令输出

4

我已经花了一整天的时间在到处搜索答案,但目前还没有找到有效的方法。我的目标是运行一个expect脚本,以附加到GNU screen会话,发送命令行参数(一个命令),并输出该命令的结果。下面是我的其中一个脚本:


#!/usr/bin/expect -f


set timeout 3
#exp_internal 1

spawn screen -raAd call_sess
sleep 1

expect -re "\\\$" {
  send $argv
  send "\n"
  sleep 1
}

expect -re ".*" {
    set output $expect_out(0,string)
}

expect "\$" {
  send "\001"
  send "d"
}

expect eof {
  puts "OUTPUT---------------"
  puts $output
  puts "OUTPUT---------------"
}

$expect_out(0,string) 仅匹配换行符,虽然 .* 应该匹配自上次匹配以来的所有内容。如果有人能帮我解决这个问题,那就太好了,我几乎要放弃并认为它是不可能的。

编辑:在评论中已经解答,但我应该指出命令确实在屏幕中运行,我只是无法正确获取输出。

编辑2:根据建议将脚本更改为生成屏幕,谢谢!


这只是一个猜测:在发送 $argv 后,您是否应该发送 '\r'? - Hai Vu
"\n" 用于发送命令,这一点我很确定。运行的是3.6.5-1-ARCH,不知道是否有所不同。命令被执行了,只是不能正确捕获输出。 - apottere
我对Expect不是很了解,但你可以通过将该命令的输出重定向到临时文件,然后从该文件中读取来解决问题吗? - Hai Vu
我考虑过这个,但这并不适用于所有情况。我希望这是一个简单的包装器,并且适用于任何命令。 - apottere
1个回答

2

答案中简单的部分是.*匹配空字符串,所以这被放入了expect_out

困难的部分是screen将给你整个屏幕 - 包括任何先前的命令 - 所以只找到你发送的命令的输出可能会有些困难。


但它不应该贪婪吗?或者你是在说.*只会匹配空字符串?如果是这样,那么你如何匹配更多内容? - apottere
1
这是一个贪婪匹配,只针对缓冲区中的任何内容。由于它总是会匹配某些内容,所以它不会强制要求 expect 从生成的进程中读取更多内容。更可靠的方法是期望命令结束时出现的内容(例如下一个提示符),这样您就知道操作完成了。这样 expect 将会继续从生成的进程中读取内容。 - evil otto
另外,为什么你要生成一个 shell 然后再运行 screen,而不是直接生成 screen? - evil otto
我修改了脚本以生成屏幕,没有意识到你可以这样做(不确定为什么)。 - apottere

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接