2

如何在 tcl(expect) 脚本中访问 bash 变量。

我有 bash 文件说 f1.sh 它设置了一些变量,例如

export var1=a1
export var2=a2

我需要在我的期望脚本中使用这些变量。

我尝试在我的脚本中使用它,但它不起作用

system "./f1.sh"
puts "var1 is $::env(var1)"
puts "var2 is $::env(var2)"

但这似乎不起作用。

我看到 f1.sh 中的非变量被设置为环境变量。

system "./f1.sh" << # Is this command in my script right ?

我需要如何从 tcl 文件访问这些 bash 变量。

4

4 回答 4

1

我想说这个问题比较笼统。首先,当我想在 PoserShell 中初始化 Microsoft Visual Studio 环境(使用 .cmd 脚本完成)时,我遇到了这个问题。后来,我在任何组合(Bash、Tcl、Python 等)的其他脚本语言中遇到了这个问题。

Hai Vu提供的解决方案很好。如果您从一开始就知道您需要哪些变量,那么它运作良好。但是,如果您要使用脚本来初始化某些环境,它可能包含许多变量(您甚至不需要知道这些变量,但这些变量是环境正常运行所必需的)。

一般来说,该问题的解决方案如下:

  1. 执行脚本,最后打印所有环境变量并捕获输出。
  2. 匹配“variable=value”等模式的输出行,这就是你想要得到的。
  3. 使用您的语言工具设置环境变量。

我没有现成的解决方案,但我想,与此类似的东西应该可以工作(注意,下面的片段没有经过测试 - 它们只是为了给出解决方案的想法):

  1. 执行脚本;打印变量并捕获输出(参数扩展 - {*} - 需要 Tcl 8.5,这里我们可以不用它,但我更喜欢使用它):

    set bashCommand {bash -c 'myScriptName arg1 arg2 2>&1 >/dev/null && export -p'}
    if [catch {*}${bashCommand} output] {
        set errMsg "ERROR: Failed to run script."
        append errMsg "\n" $output
        error $errMsg
    }
    
    ;# If we get here, output contains the output of "export -p" command
    
  2. 解析命令的输出:

    set vars [dict create]
    foreach line [split $output "\n"] {
        regex -- {^declare -x ([[:alpha:]_]*)=\"(.*)\"$} $line dummy var val
        ;# 3. Store var-val pair of set env var.
    }
    
  3. 存储 var-val 对或设置 env var。这里可以使用几种方法:

3.1。设置 Tcl 变量并像这样使用它们(取决于上下文):

set $var $val

或者

variable $var $val

3.2. 设置环境变量(其实是3.1的子案例):

global ::env
set ::env($var) $val

3.3 设置 dict 或 array 并在您的应用程序(或脚本)中使用它而不修改全局环境:

set myEnv($var) val          ;# set array
dict set myEnvDict $var $val ;# set dict

我想重复一遍,这只是收据的想法。更重要的是,由于大多数现代脚本语言都支持正则表达式,因此该收据可以在几乎任意语言对之间提供桥梁,而不仅仅是 Bash<->Tcl

于 2013-07-29T20:15:33.273 回答
0

也许我看起来不够努力,但我没有看到任何方法可以做到这一点。当您执行 bash 脚本时,您会创建一个不同的进程。该进程中发生的事情不会传播回当前进程。

我们可以通过执行以下操作来解决这个问题(感谢 potrzebie 的想法):

  1. 将 bash 脚本复制到临时脚本
  2. 将一些命令附加到临时脚本末尾以回显标记,以及变量列表及其值
  3. 执行临时脚本并解析输出
  4. 结果是交替名称和值的列表。我们使用这个列表来为我们的进程设置环境变量。

    #!/usr/bin/env tclsh
    
    package require fileutil
    
    # Execute a bash script and extract some environment variables
    proc getBashVar {bashScript varsList} {
        # Duplicate the bash script to a temp script
        set tempScriptName [fileutil::tempfile getBashVar]
        file copy -force $bashScript $tempScriptName
    
        # Append a marker to the end of the script. We need this marker to
        # identify where in the output to begin extracting the variables.
        # After that append the list of specified varibles and their values.
        set f [open $tempScriptName a]
        set marker "#XXX-MARKER"
        puts $f "\necho \\$marker"
        foreach var $varsList {
            puts $f "echo $var  \\\"$$var\\\" "
        }
        close $f
    
        # Execute the temp script and parse the output
        set scriptOutput [exec bash $tempScriptName]
        append pattern $marker {\s*(.*)}
        regexp $pattern $scriptOutput all vars
    
        # Set the environment
        array set ::env $vars
    
        # Finally, delete the temp script to clean up
        file delete $tempScriptName
    }
    
    # Test
    getBashVar f1.sh {var1 var2}
    puts "var1 = $::env(var1)"
    puts "var2 = $::env(var2)"
    
于 2013-07-28T16:57:17.670 回答
0

导出的变量仅从父进程传递给它的子进程,而不是相反。脚本 f1.sh (实际上是运行脚本的 bash 实例)获取它自己的副本,var1并且var2无论它是否更改它们,更改在退出时都会丢失。要使变量导出工作,您需要从 bash 脚本启动期望脚本。

在 f1.sh 中,printf你要返回的内容...

printf '%s\n%s\n' "$var1" "$var2"

...并在 Tcl 中使用exec阅读它:

lassign [split [exec ./f1.sh] \n] var1 var2
于 2013-07-26T16:15:38.750 回答
0

您可以使用here-document,如下所示:

#!/bin/bash
process=ssh
expect <<EOF
  spawn $process
  ...
EOF
于 2013-07-26T13:50:35.347 回答