TCL跨脚本调用报标准输出被重定向错误及文件描述符捕获问题
TCL脚本内调用另一TCL脚本报错解决方案
报错原因
使用open {|命令}语法创建管道时,TCL默认会为目标命令创建可读通道以捕获输出,你的命令中通过>& FileB.log直接将标准输出、标准错误全部重定向到本地文件,同时添加&将进程放入后台,导致TCL无法关联到命令的输出通道,因此触发can't read output from command: standard output was redirected.报错。
解决方案
分两种常用场景选择对应实现:
场景1:仅需后台执行FileB.tcl,输出全部存入日志,无需在FileA.tcl中捕获处理
直接用exec命令替代open管道即可,示例代码:
# 直接后台执行,所有输出写入FileB.log,无报错 exec FileB.tcl >& FileB.log & # 若需要获取后台进程ID用于后续管理,可以用变量接收返回值 set b_pid [exec FileB.tcl >& FileB.log &]
场景2:既要把输出写入日志,又要在FileA.tcl中实时捕获输出做业务处理
不要在调用命令中直接重定向输出,通过TCL管道通道自行处理输出分发:
- 首先创建管道通道和日志句柄:
# 打开管道,2>&1表示合并标准输出和标准错误,r表示只读模式打开通道 set b_pipe [open "|FileB.tcl 2>&1" r] # 配置通道为非阻塞、行缓冲,避免卡住FileA主进程 fconfigure $b_pipe -blocking 0 -buffering line # 打开日志文件句柄 set log_fd [open "FileB.log" w] # 绑定管道可读事件,有输出时触发回调函数 fileevent $b_pipe readable [list process_b_output $b_pipe $log_fd]
- 实现输出处理回调函数:
proc process_b_output {pipe log_fd} { # 管道读取到末尾则关闭所有句柄 if {[eof $pipe]} { close $pipe close $log_fd return } # 读取一行输出 if {[gets $pipe line] >= 0} { # 此处可添加自定义输出处理逻辑,比如匹配关键字触发操作 # 输出写入日志文件 puts $log_fd $line # 如需同时打印到FileA的控制台,添加:puts $line } }
文件描述符捕获说明
- 合并捕获标准输出、标准错误:打开管道时添加
2>&1参数即可,所有输出都会流入管道通道的读端 - 单独捕获不同输出:TCL 8.5及以上版本支持将不同文件描述符重定向到TCL已打开的句柄,示例如下:
# 分别创建标准输出、标准错误对应的日志文件句柄 set out_log [open "FileB.stdout" w] set err_log [open "FileB.stderr" w] # 调用命令时分别绑定对应输出 set b_pid [exec FileB.tcl >@$out_log 2>@$err_log &]
内容的提问来源于stack exchange,提问作者Manoj Kumar
相关产品推荐
相关产品推荐

