从第N行执行TCL脚本

时间:2019-05-30 06:42:03

标签: shell tcl

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

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

类似:     source a.tcl -line 11

我该怎么做?

2 个答案:

答案 0 :(得分: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表示第一步之后(例如,第十步之后)的保持/继续点。
  3. 基于nextSteps创建一个协程allSteps
  4. 以不会引起重新定义的方式保护proccoroutine的定义(当步骤待处理时)

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

% source script.tcl
1
2
3

现在,执行您的手动检查。然后,从同一外壳中继续:

% source script.tcl
4
5
6

请注意,您可以运行整个两阶段序列任意次(由于协程proc:rename的自我清除):

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

再次:所有这些都假定您不退出shell,并在执行审阅时维护shell。如果出于某种原因(或无法运行Tcl 8.6+)需要退出shell,那么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

答案 1 :(得分:0)

最简单的方法是打开文本文件,解析它以获得第一个 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文件,那么您已经在该限制之内…