【问题标题】:Executing a TCL script from line N从第 N 行执行 TCL 脚本
【发布时间】:2019-05-30 06:42:03
【问题描述】:

我有一个 TCL 脚本,其中包含 30 行自动化代码,我在 dc shell(Synopsys 设计编译器)中执行这些代码。我想在第 10 行停止并退出脚本,退出 dc shell 并在执行手动检查后重新启动它。但是,这一次,我想从第 11 行开始运行脚本,而不必执行前 10 行。

我不想有两个脚本,一个包含直到第 10 行的代码,另一个包含其余的,我想只使用一个脚本并尝试从第 N 行执行它。

类似: source a.tcl -line 11

我该怎么做?

【问题讨论】:

  • 我会查看 trace: tcl.tk/man/tcl8.6/TclCmd/trace.htm 例如,设置一个 enterstep-trace 将要执行的命令存根到第 11 个命令,然后删除 self。
  • 这不是 Tcl 的核心特性,而且可能永远不会成为其中之一。你也不需要它……

标签: shell tcl


【解决方案1】:

如果您有 Tcl 8.6+ 并且您考虑在 Tcl coroutine 之上重新建模您的脚本,您可以在几行中实现这种延续行为。这假定您从交互式 Tcl shell(dc shell?)运行脚本。

# script.tcl
if {[info procs allSteps] eq ""} {
    # We are not re-entering (continuing), so start all over.
    proc allSteps {args} {
      yield; # do not run when defining the coroutine;
      puts 1
      puts 2
      puts 3
      yield; # step out, once first sequence of steps (1-10) has been executed
      puts 4
      puts 5
      puts 6
      rename allSteps ""; # self-clean, once the remainder of steps (11-N) have run
    }
    coroutine nextSteps allSteps
}

nextSteps; # run coroutine
  1. 将您的脚本打包到 proc 正文中 (allSteps)。
  2. 在 proc 正文中:放置 yield 以指示在您的第一步之后(例如,在第 10 步之后)的保持/继续点。
  3. 基于allSteps创建协程nextSteps
  4. 保护proccoroutine 定义,使其不会导致重新定义(当步骤未决时)

然后,启动您的交互式 shell 并运行 source script.tcl:

% source script.tcl
1
2
3

现在,进行人工审核。然后,在同一个 shell 中继续:

% source script.tcl
4
5
6

请注意,您可以多次运行整个 2 阶段序列(因为协程 proc 的自清理:rename):

% source script.tcl
1
2
3
% source script.tcl
4
5
6

再次重申:所有这些都假设您确实从 shell 退出,并在执行审查时维护您的 shell。如果您出于某种原因需要退出 shell(或者您无法运行 Tcl 8.6+),那么 Donal 的建议是可行的方法。

更新

如果适用于您的情况,您可以使用anonymous (lambda) proc 改进实施。这简化了生命周期管理(避免重新定义、管理协程和 proc,不需要rename):

# script.tcl
if {[info commands nextSteps] eq ""} {
    # We are not re-entering (continuing), so start all over.
    coroutine nextSteps apply {args {
      yield; # do not run when defining the coroutine;
      puts 1
      puts 2
      puts 3
      yield; # step out, once first sequence of steps (1-10) has been executed
      puts 4
      puts 5
      puts 6
    }}
}

nextSteps

【讨论】:

  • 在使用一些终端会话多路复用器(tmux,screen)时,持久化shell的限制可以明显放宽。
【解决方案2】:

最简单的方法是打开文本文件,解析它以获得前 N 个命令(info complete 在那里很有用),然后评估这些(或脚本的其余部分)。当您删除尾部时,与删除前缀时相比,有效地执行此操作会产生稍微不同的代码。

proc ReadAllLines {filename} {
    set f [open $filename]
    set lines {}
    # A little bit careful in case you're working with very large scripts
    while {[gets $f line] >= 0} {
        lappend lines $line
    }
    close $f
    return $lines
}

proc SourceFirstN {filename n} {
    set lines [ReadAllLines $filename]
    set i 0
    set script {}
    foreach line $lines {
        append script $line "\n"
        if {[info complete $script] && [incr i] >= $n} {
            break              
        }
    }
    info script $filename
    unset lines
    uplevel 1 $script
}

proc SourceTailN {filename n} {
    set lines [ReadAllLines $filename]
    set i 0
    set script {}
    for {set j 0} {$j < [llength $lines]} {incr j} {
        set line [lindex $lines $j]
        append script $line "\n"
        if {[info complete $script]} {
            if {[incr i] >= $n} {
                info script $filename
                set realScript [join [lrange $lines [incr j] end] "\n"]
                unset lines script
                return [uplevel 1 $realScript]
            }
            # Dump the prefix we don't need any more
            set script {}
        }
    }
    # If we get here, the script had fewer than n lines so there's nothing to do
}

请注意,您正在处理的文件类型可能会变得非常大,并且 Tcl 目前有一些硬内存限制。另一方面,如果你完全可以source 文件,那么你已经在这个限制之内了……

【讨论】:

  • 我试试看。
  • 另外,顺便说一句,这不应该是每个人都可以使用的功能吗?
  • @batssassin 现实中的证据表明几乎没有人想要它;你是第一个问我能想到的。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-10-09
  • 1970-01-01
  • 2021-05-20
相关资源
最近更新 更多