将所有变量从一个shell脚本传递到另一个?

时间:2012-03-19 14:30:24

标签: bash shell

假设我有一个名为test.sh的shell / bash脚本:

#!/bin/bash

TESTVARIABLE=hellohelloheloo
./test2.sh

我的test2.sh看起来像这样:

#!/bin/bash

echo ${TESTVARIABLE}

这不起作用。我不想将所有变量作为参数传递,因为imho这是过度杀伤。

有不同的方式吗?

7 个答案:

答案 0 :(得分:231)

您基本上有两种选择:

  1. 在执行第二个脚本之前,使变量成为环境变量(export TESTVARIABLE)。
  2. 获取第二个脚本,即. test2.sh,它将在同一个shell中运行。这样可以让您轻松地共享更复杂的变量,如数组,但也意味着其他脚本可以修改源shell中的变量。
  3. <强>更新

    要使用export设置环境变量,您可以使用现有变量:

    A=10
    # ...
    export A
    

    这应该适用于bashshbash也允许它像这样组合:

    export A=10
    

    这也适用于我的 sh(恰好是bash,您可以使用echo $SHELL进行检查)。但我不相信这保证会在所有sh中起作用,所以最好安全地将它们分开。

    以这种方式导出的任何变量都将在您执行的脚本中可见,例如:

    <强> a.sh:

    #!/bin/sh
    
    MESSAGE="hello"
    export MESSAGE
    ./b.sh
    

    <强> b.sh:

    #!/bin/sh
    
    echo "The message is: $MESSAGE"
    

    然后:

    $ ./a.sh
    The message is: hello
    

    这些都是shell脚本的事实也只是偶然的。环境变量可以传递给您执行的任何进程,例如,如果我们使用python,它可能看起来像:

    <强> a.sh:

    #!/bin/sh
    
    MESSAGE="hello"
    export MESSAGE
    ./b.py
    

    <强> b.py:

    #!/usr/bin/python
    
    import os
    
    print 'The message is:', os.environ['MESSAGE']
    

    <强>采购:

    相反,我们可以这样来源:

    <强> a.sh:

    #!/bin/sh
    
    MESSAGE="hello"
    
    . ./b.sh
    

    <强> b.sh:

    #!/bin/sh
    
    echo "The message is: $MESSAGE"
    

    然后:

    $ ./a.sh
    The message is: hello
    

    这或多或少直接“导入”b.sh的内容并在相同的shell 中执行它。请注意,我们不必导出变量来访问它。这隐式共享您拥有的所有变量,并允许其他脚本在shell中添加/删除/修改变量。当然,在此模型中,您的脚本应该是相同的语言(shbash)。举例说明我们如何来回传递消息:

    <强> a.sh:

    #!/bin/sh
    
    MESSAGE="hello"
    
    . ./b.sh
    
    echo "[A] The message is: $MESSAGE"
    

    <强> b.sh:

    #!/bin/sh
    
    echo "[B] The message is: $MESSAGE"
    
    MESSAGE="goodbye"
    

    然后:

    $ ./a.sh
    [B] The message is: hello
    [A] The message is: goodbye
    

    这在bash中同样有效。它还可以轻松地共享更复杂的数据,这些数据无法表达为环境变量(至少没有繁重的工作),如数组或关联数组。

答案 1 :(得分:23)

致命错误给出了直接的可能性:来源你的第二个脚本!如果您担心第二个脚本可能会改变您的一些宝贵变量,您可以随时在子shell中找到它:

( . ./test2.sh )

括号将使源发生在子shell中,这样父shell就不会看到test2.sh可能执行的修改。


这里还有另一种可能性:使用set -a

来自POSIX set reference

  

-a:启用此选项时,应为要执行分配的每个变量设置 export 属性;请参阅IEEE Std 1003.1-2001的基本定义卷,Section 4.21, Variable Assignment。如果赋值在命令中的实用程序名称之前,则 export 属性在实用程序完成后不会在当前执行环境中保留,除了前面的一个特殊内置实用程序导致< em> export 属性在内置完成后保持不变。如果赋值不在命令中的实用程序名称之前,或者赋值是 getopts read 实用程序的操作的结果,则export属性将持续到变量未设置。

来自Bash Manual

  

-a:标记修改或创建的变量和函数,以便导出到后续命令的环境中。

所以在你的情况下:

set -a
TESTVARIABLE=hellohelloheloo
# ...
# Here put all the variables that will be marked for export
# and that will be available from within test2 (and all other commands).
# If test2 modifies the variables, the modifications will never be
# seen in the present script!
set +a

./test2.sh

 # Here, even if test2 modifies TESTVARIABLE, you'll still have
 # TESTVARIABLE=hellohelloheloo

观察规范仅指定set -a变量标记为以便导出。那就是:

set -a
a=b
set +a
a=c
bash -c 'echo "$a"'

将回显c而不是空行也不b(即set +a不会取消标记以进行导出,也不会“保存”作业的值仅适用于导出的环境)。当然,这是最自然的行为。

结论:使用set -a / set +a比手动导出所有变量要简单得多。它优于第二个脚本,因为它适用于任何命令,而不仅仅是用同一shell语言编写的命令。

答案 2 :(得分:13)

实际上比导出和取消设置或再次采购更简单(至少在bash中,只要你手动传递环境变量就可以了):

让a.sh成为

#!/bin/bash
secret="winkle my tinkle"
echo Yo, lemme tell you \"$secret\", b.sh!
Message=$secret ./b.sh

和b.sh是

#!/bin/bash
echo I heard \"$Message\", yo

观察到的输出是

  

[rob @ Archie测试] $ ./a.sh
  哟,lemme告诉你“我的叮当声”,b.sh!
  我听到了“眨眼”,哟

神奇之处在于a.sh的最后一行,其中Message仅在调用./b.sh期间被设置为secret的值{ a.sh。 基本上,它有点像命名参数/参数。不仅如此,它甚至适用于像$DISPLAY这样的变量,它控制应用程序启动的X服务器。

请记住,环境变量列表的长度不是无限的。在我的具有相对香草内核的系统上,xargs --show-limits告诉我参数缓冲区的最大大小为2094486字节。从理论上讲,如果您的数据大于(管道,任何人?),那么您使用的shell脚本是错误的。

答案 3 :(得分:7)

在Bash中,如果您在子shell中导出变量,使用如图所示的括号,则可以避免泄漏导出的变量:

#!/bin/bash

TESTVARIABLE=hellohelloheloo
(
export TESTVARIABLE    
source ./test2.sh
)

这样做的好处是,从命令行运行脚本后,您不会看到泄漏到您环境中的$ TESTVARIABLE:

$ ./test.sh
hellohelloheloo
$ echo $TESTVARIABLE
                            #empty! no leak
$

答案 4 :(得分:5)

添加致命错误的答案,还有一种方法可以将变量传递给另一个shell脚本。

以上建议的解决方案有一些缺点:

  1. using Export:它会导致变量超出其范围,这不是一个好的设计实践。
  2. using Source:它可能会导致名称冲突或意外覆盖某些其他shell脚本文件中的预定义变量,这些变量已导出另一个文件。
  3. 我们可以使用另一个简单的解决方案。 考虑到您发布的示例,

    <强> test.sh

    #!/bin/bash
    
    TESTVARIABLE=hellohelloheloo
    ./test2.sh "$TESTVARIABLE"
    

    <强> test2.sh

    #!/bin/bash
    
    echo $1
    

    输出

    hellohelloheloo
    

    另外需要注意的是,如果我们传递多字符串字符串,""是必需的。 再举一个例子

    <强> master.sh

    #!/bin/bash
    echo in master.sh
    var1="hello world"
    sh slave1.sh $var1
    sh slave2.sh "$var1"
    echo back to master
    

    <强> slave1.sh

    #!/bin/bash
    echo in slave1.sh
    echo value :$1
    

    <强> slave2.sh

    #!/bin/bash
    echo in slave2.sh
    echo value : $1
    

    <强>输出

    in master.sh
    in slave1.sh
    value :"hello
    in slave2.sh
    value :"hello world"
    

    这是因为this link

    中恰当描述的原因

答案 5 :(得分:1)

另一种方式,对我来说更容易使用命名管道。命名管道提供了一种在不同进程之间同步和发送消息的方法。

A.bash:

#!/bin/bash
msg="The Message"
echo $msg > A.pipe

B.bash:

#!/bin/bash
msg=`cat ./A.pipe`
echo "message from A : $msg"

用法:

$ mkfifo A.pipe #You have to create it once
$ ./A.bash & ./B.bash # you have to run your scripts at the same time

B.bash将等待消息,一旦A.bash发送消息,B.bash将继续其工作。

答案 6 :(得分:1)

另一种选择是使用eval。这仅适用于字符串可信的情况。第一个脚本可以回显变量赋值:

echo "VAR=myvalue"

然后:

eval $(./first.sh) ./second.sh

当您要为bash设置环境变量的第二个脚本而不是并且您也不希望export变量时,这种方法特别有用,可能是因为它们是敏感的,你不希望它们持续存在。