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

时间:2013-07-26 13:43:32

标签: bash environment-variables tcl expect

如何在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 个答案:

答案 0 :(得分:1)

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

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

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

  1. 执行脚本,最后打印所有环境变量并捕获输出。
  2. 匹配模式的输出行,如“variable = value”,您希望获得的位置。
  3. 使用您所用语言的设施设置环境变量。
  4. 我没有现成的解决方案,但我想,类似于此的东西应该有用(注意,下面的代码片段没有经过测试 - 它们的目的只是为了解决方案):

    1. 执行脚本; print vars并捕获输出(参数扩展 - {*} - 需要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。这里可以使用几种方法:

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

      set $var $val
      

      variable $var $val
      

      3.2。设置环境变量(实际上,3.1的子案例):

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

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

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

      我想再说一遍,这只是收据的想法。更重要的是,由于大多数现代脚本语言都支持正则表达式,因此这个收据可以提供几乎任意一对语言之间的桥梁,但不仅仅是Bash&lt; - &gt; Tcl

答案 1 :(得分:0)

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

#!/bin/bash
process=ssh
expect <<EOF
  spawn $process
  ...
EOF

答案 2 :(得分:0)

导出的变量只从父进程传递给它的子进程,而不是相反。脚本f1.sh(实际上是运行脚本的bash实例)获取了自己的var1var2副本,如果它们更改它们无关紧要,则退出时更改将丢失。要使变量导出起作用,您需要从bash脚本启动expect脚本。

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

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

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

lassign [split [exec ./f1.sh] \n] var1 var2

答案 3 :(得分:0)

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

我们可以通过以下方式解决这个问题(感谢potrzebie的想法):

  1. 将bash脚本复制到临时脚本
  2. 在temp脚本末尾添加一些命令以回显标记,以及变量及其值的列表
  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)"