我可以将变量从 Bash 脚本导出到环境而不使用它吗?

Posted

技术标签:

【中文标题】我可以将变量从 Bash 脚本导出到环境而不使用它吗?【英文标题】:Can I export a variable to the environment from a Bash script without sourcing it? 【发布时间】:2013-05-13 03:42:50 【问题描述】:

假设我有这个脚本:

export.bash

#! /usr/bin/env bash
export VAR="HELLO, VARIABLE"

当我执行脚本并尝试访问$VAR 时,我没有得到任何值!

echo $VAR

有没有办法通过执行 export.bash 来访问$VAR 而无需获取它?

【问题讨论】:

您可以尝试使用别名而不是脚本来定义您的变量。 我正在处理的脚本是某种 java 虚拟管理器,我做一些计算然后我应该将 $JAVA_HOME 导出到 env,并将其附加到 PATH。 > 嗯,您可以将信息写入文件,然后再将其读回,但采购似乎要容易得多。 子进程不能改变其父进程的环境。父母必须选择改变自己(sourceeval 或 ...) 要阅读更多源代码,man source 将不起作用,因为source 内置于 bash,您需要运行 help source 【参考方案1】:

有没有什么方法可以访问$VAR,只需执行export.bash 而不使用它?

快速回答:没有。

但有几种可能的解决方法。

您已经提到的最明显的一个是使用source. 在调用shell 的上下文中执行脚本:

$ cat set-vars1.sh 
export FOO=BAR
$ . set-vars1.sh 
$ echo $FOO
BAR

另一种方法是让脚本,而不是设置环境变量,打印将设置环境变量的命令:

$ cat set-vars2.sh
#!/bin/bash
echo export FOO=BAR
$ eval "$(./set-vars2.sh)"
$ echo "$FOO"
BAR

第三种方法是使用脚本在内部设置环境变量,然后使用该环境调用指定的命令:

$ cat set-vars3.sh
#!/bin/bash
export FOO=BAR
exec "$@"
$ ./set-vars3.sh printenv | grep FOO
FOO=BAR

最后一种方法可能非常有用,尽管它不方便交互式使用,因为它没有为您提供当前 shell 中的设置(以及您建立的所有其他设置和历史记录)。

【讨论】:

你能解释一下关于exec "$@"printenv的第三种方法吗?另外,在脚本需要一些参数的情况下,如何使用第 2 和第 3 方法? 我有一个脚本需要一些参数。 sudo . dd.sh $source $pathToUsb command not found 或 eval "$(sudo dd.sh $source $pathToUsb)" sh: 1: eval: File: not found sh: 2: eval: File: not found 或者如果尝试 ./dd.sh $source $pathToUsb printenv | grep line can't exec "@" 。有什么想法吗? . 命令内置在 shell 中,因此sudo 看不到它。您的第二个命令将尝试eval sudo dd.sh ... 命令的输出,我不知道该输出是什么样的。 dd.sh 是否打印可以由 shell 评估的命令? 你能澄清一下吗:“没有给你当前shell中的设置”? @Erwann 在我使用的示例中,执行的命令是printenv,仅受环境变量影响。但是,如果您调用交互式 shell 而不是 printenv,那么您将拥有一个新的 shell 进程,它不会继承您当前 shell 的历史记录(可能通过 $HISTFILE 除外)、未导出的变量、后台作业等。 【参考方案2】:

为了首先导出 VAR 变量,最合乎逻辑且可行的方法是 source 变量:

. ./export.bash

source ./export.bash

现在,当从主 shell 回显时,它可以工作了:

echo $VAR
HELLO, VARIABLE

我们现在将重置 VAR:

export VAR=""
echo $VAR

现在我们将执行一个脚本来获取变量,然后取消设置它:

./test-export.sh
HELLO, VARIABLE
--
.

代码:文件test-export.sh

#!/bin/bash
# Source env variable
source ./export.bash

# echo out the variable in test script
echo $VAR

# unset the variable
unset VAR
# echo a few dotted lines
echo "---"
# now return VAR which is blank
echo $VAR

这是一种方法:

请注意:导出仅限于在主控制台中执行导出的脚本 - 至于 cron 作业,我会像下面的控制台一样添加它...对于命令部分仍然值得怀疑:这是从 shell 运行的方式:

在您的命令提示符下(只要 export.bash 文件 有多个回显值)

IFS=$'\n'; for entries in $(./export.bash); do  export $entries;  done; ./v1.sh
HELLO THERE
HI THERE

文件猫 v1.sh

#!/bin/bash
echo $VAR
echo $VAR1

现在,只要这是供您使用的 - 您可以随时通过执行这样的 Bash 别名使变量可用于您的脚本:

myvars ./v1.sh
HELLO THERE
HI THERE

echo $VAR

.

将此添加到您的.bashrc file

function myvars() 
    IFS=$'\n';
    for entries in $(./export.bash); do  export $entries;  done;

    "$@";

    for entries in $(./export.bash); do variable=$(echo $entries|awk -F"=" 'print $1'); unset $variable;
    done

Source你的 .bashrc 文件,你可以随时像上面那样做......

不管怎样,回到它的其余部分......

这使它全局可用,然后执行脚本...

只需将其回显并在回显上运行导出!

文件export.bash

#!/bin/bash
echo "VAR=HELLO THERE"

现在在脚本或您的控制台中运行:

export "$(./export.bash)"

试试:

echo $VAR
HELLO THERE

只要您知道使用上述方法在另一个脚本中期望什么,就可以有多个值:

文件export.bash

#!/bin/bash
echo "VAR=HELLO THERE"
echo "VAR1=HI THERE"

文件 test-export.sh

#!/bin/bash

IFS=$'\n'
for entries in $(./export.bash); do
    export $entries
done

echo "round 1"
echo $VAR
echo $VAR1

for entries in $(./export.bash); do
    variable=$(echo $entries|awk -F"=" 'print $1');
    unset $variable
done

echo "round 2"
echo $VAR
echo $VAR1

现在结果

./test-export.sh
round 1
HELLO THERE
HI THERE
round 2


.

以及自动分配的最终最终更新,请阅读变量:

./test-export.sh
Round 0 - Export out then find variable name -
Set current variable to the variable exported then echo its value
$VAR has value of HELLO THERE
$VAR1 has value of HI THERE
round 1 - we know what was exported and we will echo out known variables
HELLO THERE
HI THERE
Round 2 - We will just return the variable names and unset them
round 3 - Now we get nothing back

脚本:

文件 test-export.sh

#!/bin/bash

IFS=$'\n'
echo "Round 0 - Export out then find variable name - "
echo "Set current variable to the variable exported then echo its value"
for entries in $(./export.bash); do
    variable=$(echo $entries|awk -F"=" 'print $1');
    export $entries
    eval current_variable=\$$variable
    echo "\$$variable has value of $current_variable"
done


echo "round 1 - we know what was exported and we will echo out known variables"
echo $VAR
echo $VAR1

echo "Round 2 - We will just return the variable names and unset them "
for entries in $(./export.bash); do
    variable=$(echo $entries|awk -F"=" 'print $1');
    unset $variable
done

echo "round 3 - Now we get nothing back"
echo $VAR
echo $VAR1

【讨论】:

我想通过执行文件来导出 VAR,而不是通过获取它。 @vahid 你应该解释一下你的脚本在做什么。 为什么不在采购后取消设置变量?这比您尝试给自己造成的痛苦会更新测试导出脚本要容易得多 我提供了另一种方法 Tarrsalah 好的最终更新 - 建议的方法和解决 bashrc 别名想法的问题可能是一个很好的方法【参考方案3】:

执行

set -o allexport

在此之后您从文件中获取的任何变量都将导出到您的 shell 中。

source conf-file

完成后执行。这将禁用 allexport 模式。

set +o allexport

【讨论】:

问题的重点是“如何在没有源的情况下导出”。此答案使用来源。 @ekkis 是的,它并没有完全回答这个问题,但是每当我用谷歌搜索如何从文件中导出变量时,就会出现这个线程。所以我只是把它放在那里。 我对此表示赞同,因为最初的问题陈述让我明白这是我的基本解决方案。这里有关于 allexport 的官方文档:gnu.org/software/bash/manual/html_node/The-Set-Builtin.html【参考方案4】:

我发现了一种从文件中导出环境变量的有趣而简洁的方法:

在文件env.vars中:

foo=test

测试脚本:

eval `cat env.vars`
echo $foo         # => test
sh -c 'echo $foo' # =>

export eval `cat env.vars`
echo $foo         # => test
sh -c 'echo $foo' # => test

# a better one. "--" stops processing options,
# key=value list given as parameters
export -- `cat env.vars`
echo $foo         # => test
sh -c 'echo $foo' # => test

【讨论】:

【参考方案5】:

另一种解决方法,取决于具体情况,它可能有用:创建另一个继承导出变量的 bash 脚本。这是Keith Thompson's answer的一个特例,将所有这些缺点。

文件导出.bash:

# !/bin/bash
export VAR="HELLO, VARIABLE"
bash

现在:

./export.bash
echo $VAR

【讨论】:

你确定你写的东西有用吗!?我相信你必须执行行命令:. ./export.bash @Sir Jo Black,是的,当然。 export.bash 文件的最后一行调用bash 作为当前shell 的子级。并且由于之前已导出 VAR,因此该调用将包含该变量。当然,如果你输入exitVAR 就会消失。你检查了吗? 好的!我还没有看到那个调用......:p【参考方案6】:

答案是否定的,但对我来说,我做了以下

脚本:

我的出口

#! \bin\bash
export $1

我.bashrc file中的别名:

alias myExport='source myExport'

还是你source它,但也许这样它更有用,对其他人来说很有趣。

【讨论】:

【参考方案7】:

也许你可以在~/.zshrc~/.bashrc中添加一个函数。

# set my env
[ -s ~/.env ] && export MYENV=`cat ~/.env`
function myenv()  [[ -s ~/.env ]] && echo $argv > ~/.env && export MYENV=$argv 

由于使用了外部变量,可以避免使用脚本文件。

【讨论】:

【参考方案8】:

我不认为这可以做到,但我找到了使用alias 的解决方法。仅当您将脚本放在脚本目录中时,它才会起作用。否则,您的别名将具有无效名称。

解决方法的唯一要点是能够在具有相同名称的文件中拥有一个函数,并且在使用它之前不必费心寻找它。将以下代码添加到文件~/.bashrc

alias myFunction='unalias myFunction && . myFunction && myFunction "$@"'

您现在可以在没有sourcing 的情况下先调用myFunction

【讨论】:

【参考方案9】:

这种解决方法在其他地方以某种方式暗示,但可能不是那么清楚:

在您的脚本中,设置变量后,启动一个新的 shell,而不是返回。

我的用例是我打开了许多终端,其中一些我想要一些变量的值,而在另一些我想要其他值。

由于使用source 可能更难记住,这种方法的一个小优势是当您需要一段时间才能意识到您忘记使用source,并且您必须从头开始。

(对我来说,使用source script 更有意义,因为丢失的变量会立即被发现。)

【讨论】:

以上是关于我可以将变量从 Bash 脚本导出到环境而不使用它吗?的主要内容,如果未能解决你的问题,请参考以下文章

从带有参数的bash脚本中导出环境变量

如何使用sudo将环境变量导出到后台进程? [重复]

Bash - 使用特殊字符 ($) 导出环境变量

bash - 转义变量SSH命令而不改变它

bash 变量何时导出到子 shell 和/或脚本可访问?

按内容从bash数组中删除元素(存储在变量中)而不留下空白槽[重复]