将所有变量从一个shellcript传递到另一个shellcript?

Tos*_*kan 174 bash shell

所以假设我有一个名为test.sh的shellscript/bash脚本

有:

#!/bin/bash

TESTVARIABLE=hellohelloheloo
./test2.sh
Run Code Online (Sandbox Code Playgroud)

我的test2.sh看起来像这样

#!/bin/bash

echo ${TESTVARIABLE}
Run Code Online (Sandbox Code Playgroud)

这不起作用.我不想将所有变量作为参数传递,因为imho这是过度的.有不同的方式吗?

Fat*_*ror 243

你基本上有两个选择:

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

更新:

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

A=10
# ...
export A
Run Code Online (Sandbox Code Playgroud)

这应该适用于bashsh. bash也允许它像这样组合:

export A=10
Run Code Online (Sandbox Code Playgroud)

这也适用于 sh(恰好是bash你可以echo $SHELL用来检查).但我不相信这一点可以保证在所有方面都有效sh,所以最好安全地将它们分开.

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

灰:

#!/bin/sh

MESSAGE="hello"
export MESSAGE
./b.sh
Run Code Online (Sandbox Code Playgroud)

b.sh:

#!/bin/sh

echo "The message is: $MESSAGE"
Run Code Online (Sandbox Code Playgroud)

然后:

$ ./a.sh
The message is: hello
Run Code Online (Sandbox Code Playgroud)

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

灰:

#!/bin/sh

MESSAGE="hello"
export MESSAGE
./b.py
Run Code Online (Sandbox Code Playgroud)

b.py:

#!/usr/bin/python

import os

print 'The message is:', os.environ['MESSAGE']
Run Code Online (Sandbox Code Playgroud)

采购:

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

灰:

#!/bin/sh

MESSAGE="hello"

. ./b.sh
Run Code Online (Sandbox Code Playgroud)

b.sh:

#!/bin/sh

echo "The message is: $MESSAGE"
Run Code Online (Sandbox Code Playgroud)

然后:

$ ./a.sh
The message is: hello
Run Code Online (Sandbox Code Playgroud)

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

灰:

#!/bin/sh

MESSAGE="hello"

. ./b.sh

echo "[A] The message is: $MESSAGE"
Run Code Online (Sandbox Code Playgroud)

b.sh:

#!/bin/sh

echo "[B] The message is: $MESSAGE"

MESSAGE="goodbye"
Run Code Online (Sandbox Code Playgroud)

然后:

$ ./a.sh
[B] The message is: hello
[A] The message is: goodbye
Run Code Online (Sandbox Code Playgroud)

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

  • 如果我需要将 $1 传递给子 shell(因为 'sudo sh -c ...' 是从脚本调用的)怎么办?我是否必须将 $1 放入环境变量中,将其导出,然后在命令中使用该变量? (2认同)
  • @FatalError您能否在最后一个a.sh(称为“ ../b.sh”)中解释魔术。第一个圆点是什么意思?顺便说一句! (2认同)

gni*_*urf 25

致命错误提供了一个简单的可能性:来源你的第二个脚本!如果您担心第二个脚本可能会改变您的一些宝贵变量,您可以随时在子shell中获取它:

( . ./test2.sh )
Run Code Online (Sandbox Code Playgroud)

括号将使源发生在子shell中,以便父shell不会看到修改test2.sh可以执行.


还有另一种可能性,应该在这里引用:使用set -a.

POSIX set参考:

-a:启用此选项时,应为要执行分配的每个变量设置export属性; 请参阅IEEE Std 1003.1-2001的基本定义卷,第4.21节,变量分配.如果赋值在命令中的实用程序名称之前,则在实用程序完成后,export属性不会在当前执行环境中保留,除了前面的一个特殊内置实用程序导致export属性在构建之后保持不变已完成.如果赋值不在命令中的实用程序名称之前,或者赋值是getoptsread实用程序操作的结果,则export属性将持续存在,直到取消设置该变量.

Bash手册:

-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
Run Code Online (Sandbox Code Playgroud)

请注意,规范仅指定set -a将变量标记为导出.那是:

set -a
a=b
set +a
a=c
bash -c 'echo "$a"'
Run Code Online (Sandbox Code Playgroud)

将回显c而不是空行b(也就是说,set +a不会为导出取消标记,也不会仅为导出的环境"保存"赋值的值).当然,这是最自然的行为.

结论:使用set -a/ set +a可以比手动导出所有变量更乏味.它优于第二个脚本,因为它适用于任何命令,而不仅仅是用同一shell语言编写的命令.

  • `set -a` 和 `set +a` 非常有帮助!我将它与已接受的答案结合使用。效果很好。谢谢你! (3认同)

str*_*ing 17

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

让a.sh成为

#!/bin/bash
secret="winkle my tinkle"
echo Yo, lemme tell you \"$secret\", b.sh!
Message=$secret ./b.sh
Run Code Online (Sandbox Code Playgroud)

和b.sh是

#!/bin/bash
echo I heard \"$Message\", yo
Run Code Online (Sandbox Code Playgroud)

观察到的输出是

[rob @ Archie测试] $ ./a.sh
哟,lemme告诉你"winkle my tinkle",b.sh!
我听到"叮叮当当",哟

神奇之处在于最后一行a.sh,其中Message,仅在调用的持续时间内./b.sh,将其设置为secretfrom 的值a.sh.基本上,它有点像命名参数/参数.不仅如此,它甚至可以用于$DISPLAY控制应用程序启动的X服务器等变量.

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


Ria*_*zvi 7

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

#!/bin/bash

TESTVARIABLE=hellohelloheloo
(
export TESTVARIABLE    
source ./test2.sh
)
Run Code Online (Sandbox Code Playgroud)

这里的优点是,从命令行运行脚本后,您将看不到泄露到您的环境中的$ TESTVARIABLE:

$ ./test.sh
hellohelloheloo
$ echo $TESTVARIABLE
                            #empty! no leak
$
Run Code Online (Sandbox Code Playgroud)


Sub*_*thi 6

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

上面提出的解决方案有一些缺点:

  1. using Export :它会导致变量超出其范围,这不是一个好的设计实践.
  2. using Source :它可能导致名称冲突或意外覆盖某些其他shell脚本文件中的预定义变量,这些文件已经获得了另一个文件.

我们可以使用另一个简单的解决方案.考虑到您发布的示例,

test.sh

#!/bin/bash

TESTVARIABLE=hellohelloheloo
./test2.sh "$TESTVARIABLE"
Run Code Online (Sandbox Code Playgroud)

test2.sh

#!/bin/bash

echo $1
Run Code Online (Sandbox Code Playgroud)

产量

hellohelloheloo
Run Code Online (Sandbox Code Playgroud)

另外需要注意的""是,如果我们传递多字符串字符串,则必须这样做.再举一个例子

master.sh

#!/bin/bash
echo in master.sh
var1="hello world"
sh slave1.sh $var1
sh slave2.sh "$var1"
echo back to master
Run Code Online (Sandbox Code Playgroud)

slave1.sh

#!/bin/bash
echo in slave1.sh
echo value :$1
Run Code Online (Sandbox Code Playgroud)

slave2.sh

#!/bin/bash
echo in slave2.sh
echo value : $1
Run Code Online (Sandbox Code Playgroud)

产量

in master.sh
in slave1.sh
value :"hello
in slave2.sh
value :"hello world"
Run Code Online (Sandbox Code Playgroud)

这是因为此链接中恰当描述的原因

  • 使用`source`实际上是一件好事.关于你的担心:_accidental覆盖预定义的变量_,你总是可以在子shell中获取.这完全解决了这个问题. (6认同)