C 保存和还原shell变量

C 保存和还原shell变量,c,bash,shell,environment-variables,C,Bash,Shell,Environment Variables,我想从C程序中调用两个shell脚本。我希望在第一个脚本中设置的shell变量在第二个脚本中可见。下面是它的外观: a、 上海: b、 上海: 到目前为止,我想到的最好的方法是使用set>/tmp/vars上的变量来保存变量,并使用eval$cat/tmp/vars来恢复变量。eval在尝试恢复只读变量时会阻塞,因此我需要将其清除。这些变量的列表可以通过declare-r获得。但是有一些变量未显示在此列表中,但仍然无法在eval中设置,例如BASH_ARGC。所以我也需要把它们刷出来 在这一点上

我想从C程序中调用两个shell脚本。我希望在第一个脚本中设置的shell变量在第二个脚本中可见。下面是它的外观:

a、 上海:

b、 上海:

到目前为止,我想到的最好的方法是使用set>/tmp/vars上的变量来保存变量,并使用eval$cat/tmp/vars来恢复变量。eval在尝试恢复只读变量时会阻塞,因此我需要将其清除。这些变量的列表可以通过declare-r获得。但是有一些变量未显示在此列表中,但仍然无法在eval中设置,例如BASH_ARGC。所以我也需要把它们刷出来


在这一点上,我的解决方案感觉非常脆弱和容易出错,我不确定它的可移植性。有更好的方法吗?

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

不确定这是否是公认的教条,但:

bash -c 'export foo=bar; env > xxxx'
env `cat xxxx` otherscript.sh
其他脚本将把环境打印到xxxx

更新:

另请注意:

man execle
如果需要的话,介绍如何在C中为另一个系统调用设置环境变量。以及:

man getenv

如果您可以在变量名上使用通用前缀,下面是一种方法:

# 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版本而异:

导出-不带参数,使用声明格式列出所有导出的变量 declare-px-与前面的命令相同 declare-pr-列出只读变量
避免设置有问题的变量的一种方法是只存储在每个脚本执行期间更改的变量。比如说,

a、 上海:

b、 上海:

/tmp/vars包含以下内容:

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

显然,对前两行进行求值不会产生不利影响。

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

. a.sh echo "information gleaned from a" arguments_for_b=$(read -r) . b.sh C程序的总体结构是:

设置两对管道,一对用于C->shell,另一对用于shell->C fork,执行shell包装器 读取从外壳->C管道上的a收集的信息 更多处理 在C->shell管道上为b编写参数 等待子进程结束
我去寻找类似的东西,但也找不到,所以我制作了下面的两个脚本。首先,只需说shellstate,然后可能至少设置-i和set-o emacs,而这个reset\u shellstate不适合您。我不知道如何询问bash它认为哪些变量是特殊的

~/bin/reset\u外壳状态:

~/bin/shell状态:


在执行a.sh和b.sh之间,我需要在C中做一些工作,所以a不可能调用b。请注意,我感兴趣的是shell变量,而不是环境变量。这两个脚本是用户提供的,因此需要一个公共前缀会有点尴尬。另一方面,我可以检查每个脚本修改过的变量。我将在答案中加入这个想法,这样我就可以得到格式…集合将包括函数定义,declare-p不会declare-f会。请注意使用未验证或未受保护的declare(例如输入)进行eval的可能性。
set > /tmp/pre
foo=bar
set > /tmp/post
grep -v -F -f/tmp/pre /tmp/post > /tmp/vars
eval $(cat /tmp/vars)
echo $foo
PIPESTATUS=([0]="0")
_=
foo=bar
. a.sh echo "information gleaned from a" arguments_for_b=$(read -r) . b.sh
#!/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/bash
shellstate=shellstate_${1#_}
test -s $shellstate || reset_shellstate $1
shift
bash --noprofile --init-file shellstate_${1#_} -is "$@"
exit $?