bash脚本与本地环境变量命名空间冲突

bash脚本与本地环境变量命名空间冲突

我有一个bash script名为VAR_A

我也有一个当地人env variableVAR_A

调用bash script命令:

echo ${VAR_A}

我无法将脚本中的变量更改为其他名称,但我可以更改脚本调用命令的方式echo

如何修改echo命令以确保它打印本地命令env variable而不是脚本中提供的命令?

UPDATE FOR CLARITY:

情况:

用户有一个现有.bashrc文件,在登录时设置:

VAR_A="someValue"
export VAR_A

这允许用户:

~]$ echo ${VAR_A}
    someValue

我有一些 bash 脚本的配置文件

VAR_A="someOtherValue"

我有一个 bash 脚本:

#!/bin/bash

. ../configuration  # imports config file with some values

#  do stuff

echo ${VAR_A}

从终端(作为登录用户的 bash shell)执行脚本会打印:

~]$ ./run_script.sh
    someOtherStuff

我需要它来打印:

~]$ ./run_script.sh
    someStuff

答案1

shell 变量是从每个 shell 中的环境变量初始化的,你无法绕过这一点。

当 shell 启动时,对于它接收到的每个具有有效名称作为 shell 变量的环境变量,shell 都会为相应的 shell 变量分配相应的值。例如,如果您的脚本启动为:

env VAR_A=xxx your-script

(并且有一个#!/bin/bash -she-bang),env将执行/bin/bash并传递VAR_A=xxx给该 bash 命令,并将bash为其变量分配$VAR_Avalue xxx

在 Bourne shell 和 C-shell 中,如果为该 shell 变量分配一个新值,它不会影响传递给该 shell 后续执行的命令的相应环境变量,您必须使用exportsetenv来实现这一点(但请注意在 Bourne shell 中,如果您unset使用变量,它会删除 shell 变量和环境变量)。

在:

env VAR=xxx sh -c 'VAR=yyy; other-command'

sh是 Bourne shell,而不是现代 POSIX shell)或者:

env VAR=xxx csh -c 'set VAR = yyy; other-command'

other-commandVAR=xxx在其环境中接收,而不是VAR=yyy,您需要编写它:

env VAR=xxx sh -c 'VAR=yyy; export VAR; other-command'

或者

env VAR=yyy csh -c 'setenv VAR yyy; other-command'

为了在其环境中other-command接收。VAR=yyy

然而,ksh(结果是 POSIX,然后bash是所有其他现代的类似 Bourne 的 shell)打破了这一点。

启动时那些现代 shell绑定将它们的shell变量添加到相应的环境变量中。

这意味着脚本可能仅通过设置其中一个变量来破坏环境,即使它不导出它。有些 shell 甚至会删除它无法映射到 shell 变量的环境变量(这就是为什么建议仅使用 shell 可映射的变量名称作为环境变量名称)。

这就是为什么按照惯例,所有大写变量都应该保留给环境变量的主要原因。

为了解决这个问题,如果您希望脚本执行的命令接收与解释脚本的 shell 接收到的环境相同的环境,则需要以某种方式存储该环境。您可以通过添加以下内容来做到这一点:

my_saved_env=$(export -p)

在脚本的开头,然后使用以下命令运行命令:

(eval "$my_saved_env"; exec my-other-command and its args)

boshmksh贝壳中,当地的函数中的变量不会破坏环境变量(只要你不破坏export环境变量),但请注意,使用一些特殊变量(例如HOMEfor cdPATH用于可执行文件查找...)的 shell 内置函数将使用(本地)变量,而不是环境变量。

$ env VAR=env mksh -c 'f() { local VAR=local; echo "$VAR"; printenv VAR; }; f'
local
env

答案2

VAR_A您可以通过添加一行来使变量只读:

readonly VAR_A

在脚本的顶部。这将导致 的VAR_A值为保留根据您当地的环境。

readonly: readonly [-aAf] [name[=value] ...] or readonly -p

Mark shell variables as unchangeable.

Mark each NAME as read-only; the values of these NAMEs may not be
changed by subsequent assignment.  If VALUE is supplied, assign VALUE
before marking as read-only.

Options:
  -a        refer to indexed array variables
  -A        refer to associative array variables
  -f        refer to shell functions
  -p        display a list of all readonly variables and functions

An argument of `--' disables further option processing.

Exit Status:
Returns success unless an invalid option is given or NAME is invalid.

下面的例子应该可以清楚地说明:

$ export FOO="somevalue"        # environment variable FOO set to somevalue
$ cat test                      # test script
echo $FOO                       # print the value of FOO
readonly FOO                       # set FOO to local
FOO="something"                 # attempt to modify FOO
echo $FOO                       # print the value of FOO -- you would see the value that was inherited from the environment
$ bash test
somevalue
test: line 3: FOO: readonly variable
something

答案3

如果您想打印当地的变量VAR_A,必须在其局部范围内调用,否则,它将打印全局变量的值VAR_A

#! /bin/bash 

VAR_A="I'm global"

function lexical() {
    local VAR_A="I'm lexical"
    echo $VAR_A
}

echo -n "Global VAR_A: "
echo $VAR_A
echo -n "Lexical VAR_A: "
lexical

运行:

$ ./test.sh 
Global VAR_A: I'm global
Lexical VAR_A: I'm lexical

您可以local从以下页面阅读有关 bash 的更多信息man

local [option] [name[=value] ...]
              For each argument, a local variable named name is  created,  and
              assigned  value.   The option can be any of the options accepted
              by declare.  When local is used within a function, it causes the
              variable  name  to have a visible scope restricted to that func‐
              tion and its children.  With no operands, local writes a list of
              local  variables  to the standard output.  It is an error to use
              local when not within a function.  The return status is 0 unless
              local  is  used outside a function, an invalid name is supplied,
              or name is a readonly variable.

答案4

发生的情况是配置文件VAR_A正在覆盖VAR_A来自.bashrc.

因此,解决方案本身如下:在获取配置文件之前,保存 的内容VAR_A,如下所示。

VAR_A_sav=${VAR_A} # assuming that VAR_A_sav does NOT exist in configuration

. ../configuration # that is, you must choose a name not existing in config.

VAR_A=${VAR_A_sav}

相关内容