【问题标题】:save and restore shell variables保存和恢复 shell 变量
【发布时间】:2011-03-14 12:38:38
【问题描述】:

我有两个想要从 C 程序调用的 shell 脚本。我希望在第一个脚本中设置的 shell 变量在第二个脚本中可见。这是它的样子:

a.sh:

var=blah
<save vars>

b.sh:

<restore vars>
echo $var

到目前为止,我想出的最好的方法是使用“set > /tmp/vars”来保存变量并使用“eval $(cat /tmp/vars)”来恢复它们。当它试图恢复只读变量时,“eval”会窒息,所以我需要把它们找出来。这些变量的列表可通过“declare -r”获得。但是有一些变量没有出现在这个列表中,但仍然不能在 eval 中设置,例如BASH_ARGC。所以我也需要 grep 出来。

此时,我的解决方案感觉非常脆弱且容易出错,而且我不确定它的便携性如何。有没有更好的方法来做到这一点?

【问题讨论】:

    标签: c bash shell environment-variables


    【解决方案1】:

    避免设置有问题的变量的一种方法是仅存储在每个脚本执行期间发生更改的变量。例如,

    a.sh:

    set > /tmp/pre
    foo=bar
    set > /tmp/post
    grep -v -F -f/tmp/pre /tmp/post > /tmp/vars
    

    b.sh:

    eval $(cat /tmp/vars)
    echo $foo
    

    /tmp/vars 包含以下内容:

    PIPESTATUS=([0]="0")
    _=
    foo=bar
    

    显然评估前两行没有负面影响。

    【讨论】:

    • set 将包含函数定义,declare -p 不会(declare -f 会)。请注意evalsecurity risks 输入未经验证或未受保护(例如declare)。
    【解决方案2】:

    如果你可以在你的变量名上使用一个通用前缀,这里有一种方法:

    # save the variables
    yourprefix_width=1200
    yourprefix_height=2150
    yourprefix_length=1975
    yourprefix_material=gravel
    yourprefix_customer_array=("Acme Plumbing" "123 Main" "Anytown")
    declare -p $(echo ${!yourprefix@}) > varfile
    
    # load the variables
    while read -r line
    do
        if [[ $line == declare\ * ]]
        then
            eval "$line"
        fi
    done < varfile
    

    当然,您的前缀会更短。您可以在加载变量时进行进一步验证,以确保变量名称符合您的命名方案。

    使用declare 的优势在于它比单独使用eval 更安全。

    如果需要,您可以过滤掉标记为只读的变量或选择标记为导出的变量。

    其他感兴趣的命令(有些可能因 Bash 版本而异):

    • export - 不带参数,使用declare 格式列出所有导出的变量
    • declare -px - 与上一条命令相同
    • declare -pr - 列出只读变量

    【讨论】:

    • 这两个脚本是用户提供的,所以需要一个共同的前缀会有点尴尬。另一方面,我可以只检查每个脚本修改过的变量。打算把这个想法放在答案中,这样我就可以格式化......
    【解决方案3】:

    如果 a.sh 可以调用 b.sh,如果它们被导出,它将继续。或者让父母设置所有必要的值,然后调用两者。这是我能想到的最安全可靠的方法。

    不确定它是否被接受,但是:

    bash -c 'export foo=bar; env > xxxx'
    env `cat xxxx` otherscript.sh
    

    otherscript 会将环境打印到 xxxx ...

    更新:

    另请注意:

    man execle
    

    关于如何在 C 中为另一个系统调用设置环境变量,如果需要的话。并且:

    man getenv
    

    http://www.crasseux.com/books/ctutorial/Environment-variables.html

    【讨论】:

    • 我需要在执行a.sh和b.sh之间在C中做一些工作,所以a调用b是不可能的。请注意,我对 shell 变量感兴趣,而不是环境变量。
    【解决方案4】:

    另一种保存和恢复 shell 状态的方法是让 C 程序和 shell 程序并行工作:C 程序启动运行 a.sh 的 shell 程序,然后通知 C 程序(可能传递一些信息它是从执行a.sh) 中学到的,当 C 程序准备好执行更多操作时,它会告诉 shell 程序运行b.sh。 shell 程序如下所示:

    .灰 echo "从某处收集到的信息" arguments_for_b=$(读取 -r) . b.sh

    C 程序的一般结构是:

    • 设置两对管道,一对用于C->shell,一对用于shell->C
    • fork,执行 shell 包装器
    • 读取从 shell 上的 a 收集的信息->C 管道
    • 更多处理
    • 在 C->shell 管道上为 b 编写参数
    • 等待子进程结束

    【讨论】:

      【解决方案5】:

      我去寻找类似的东西,但也找不到,所以我制作了下面的两个脚本。首先,只需说shellstate,然后可能至少说set -iset -o emacs,这reset_shellstate 不适合你。我不知道如何询问 bash 它认为哪些变量是特殊的。

      ~/bin/reset_shellstate:

      #!/bin/bash
      __="$PWD/shellstate_${1#_}"
      trap    '
          declare -p      >"'"$__"'"
          trap            >>"'"$__"'"
          echo cd \""$PWD"\"      >>"'"$__"'"     # setting PWD did this already, but...
          echo set +abefhikmnptuvxBCEHPT  >>"'"$__"'"
          echo set -$-    >>"'"$__"'"     # must be last before sed, see $s/s//2 below
          sed -ri '\''
                  $s/s//2
                  s,^trap --,trap,
                  /^declare -[^ ]*r/d
                  /^declare -[^ ]* [A-Za-z0-9_]*[^A-Za-z0-9_=]/d
                  /^declare -[^ ]* [^= ]*_SESSION_/d
                  /^declare -[^ ]* BASH[=_]/d
                  /^declare -[^ ]* (DISPLAY|GROUPS|SHLVL|XAUTHORITY)=/d
                  /^declare -[^ ]* WINDOW(ID|PATH)=/d
                  '\''    "'"$__"'"
          shopt -op       >>"'"$__"'"
          shopt -p        >>"'"$__"'"
          declare -f      >>"'"$__"'"
          echo "Shell state saved in '"$__"'"
          ' 0
      unset __
      

      ~/bin/shellstate:

      #!/bin/bash
      shellstate=shellstate_${1#_}
      test -s $shellstate || reset_shellstate $1
      shift
      bash --noprofile --init-file shellstate_${1#_} -is "$@"
      exit $?
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2011-09-27
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-11-19
        • 1970-01-01
        相关资源
        最近更新 更多