bash 为什么我不能指定一个环境变量并在同一个命令行中回显它?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/10938483/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Why can't I specify an environment variable and echo it in the same command line?
提问by sdaau
Consider this snippet:
考虑这个片段:
$ SOMEVAR=AAA
$ echo zzz $SOMEVAR zzz
zzz AAA zzz
Here I've set $SOMEVAR
to AAA
on the first line - and when I echo it on the second line, I get the AAA
contents as expected.
在这里,我在第一行设置$SOMEVAR
为AAA
- 当我在第二行回显时,我得到了AAA
预期的内容。
But then, if I try to specify the variable on the same command line as the echo
:
但是,如果我尝试在与以下命令相同的命令行上指定变量echo
:
$ SOMEVAR=BBB echo zzz $SOMEVAR zzz
zzz AAA zzz
... I do not get BBB
as I expected - I get the old value (AAA
).
...我没有得到BBB
预期的结果 - 我得到了旧值 ( AAA
)。
Is this how things are supposed to be? If so, how come then you can specify variables like LD_PRELOAD=/... program args ...
and have it work? What am I missing?
事情应该是这样的吗?如果是这样,那么您为什么可以指定变量LD_PRELOAD=/... program args ...
并使其工作?我错过了什么?
回答by Jonathan Leffler
What you see is the expected behaviour. The trouble is that the parent shell evaluates $SOMEVAR
on the command line before it invokes the command with the modified environment. You need to get the evaluation of $SOMEVAR
deferred until after the environment is set.
你看到的是预期的行为。问题在于,父shell$SOMEVAR
在使用修改后的环境调用命令之前会在命令行上进行评估。您需要$SOMEVAR
在设置环境之后才能获得延迟的评估。
Your immediate options include:
您的即时选择包括:
SOMEVAR=BBB eval echo zzz '$SOMEVAR' zzz
.SOMEVAR=BBB sh -c 'echo zzz $SOMEVAR zzz'
.
SOMEVAR=BBB eval echo zzz '$SOMEVAR' zzz
.SOMEVAR=BBB sh -c 'echo zzz $SOMEVAR zzz'
.
Both these use single quotes to prevent the parent shell from evaluating $SOMEVAR
; it is only evaluated after it is set in the environment (temporarily, for the duration of the single command).
这两个都使用单引号来防止父 shell 评估$SOMEVAR
;它仅在环境中设置后才进行评估(临时,在单个命令的持续时间内)。
Another option is to use the sub-shell notation (as also suggested by Marcus Kuhnin his answer):
另一种选择是使用 sub-shell 符号(正如Marcus Kuhn在他的回答中所建议的那样):
(SOMEVAR=BBB; echo zzz $SOMEVAR zzz)
The variable is set only in the sub-shell
该变量仅在子shell中设置
回答by Todd A. Jacobs
The Problem, Revisited
问题,重新审视
Quite frankly, the manual is confusing on this point. The GNU Bash manualsays:
坦率地说,手册在这一点上令人困惑。在GNU Bash的手册说:
The environment for any simple command or function [note that this excludes builtins] may be augmented temporarily by prefixing it with parameter assignments, as described in Shell Parameters. These assignment statements affect only the environment seen by that command.
任何简单命令或函数的环境[请注意,这不包括内置函数] 可以通过在其前面加上参数分配来临时增强,如外壳参数中所述。这些赋值语句仅影响该命令看到的环境。
If you really parse the sentence, what it's saying is that the environmentfor the command/function is modified, but not the environment for the parent process. So, this will work:
如果你真的解析这句话,什么它说的是环境的命令/函数进行了修改,但不适用于父进程的环境。所以,这将起作用:
$ TESTVAR=bbb env | fgrep TESTVAR
TESTVAR=bbb
because the environment for the env command has been modified before it executed. However, this will not work:
因为 env 命令的环境在执行之前已经被修改了。但是,这不起作用:
$ set -x; TESTVAR=bbb echo aaa $TESTVAR ccc
+ TESTVAR=bbb
+ echo aaa ccc
aaa ccc
because of when parameter expansion is performed by the shell.
因为参数扩展是由 shell 执行的。
Interpreter Steps
口译步骤
Another part of the problem is that Bash defines these stepsfor its interpreter:
问题的另一部分是 Bash为其解释器定义了这些步骤:
- Reads its input from a file (see Shell Scripts), from a string supplied as an argument to the -c invocation option (see Invoking Bash), or from the user's terminal.
- Breaks the input into words and operators, obeying the quoting rules described in Quoting. These tokens are separated by metacharacters. Alias expansion is performed by this step (see Aliases).
- Parses the tokens into simple and compound commands (see Shell Commands).
- Performs the various shell expansions (see Shell Expansions), breaking the expanded tokens into lists of filenames (see Filename Expansion) and commands and arguments.
- Performs any necessary redirections (see Redirections) and removes the redirection operators and their operands from the argument list.
- Executes the command (see Executing Commands).
- Optionally waits for the command to complete and collects its exit status (see Exit Status).
- 从文件(请参阅 Shell 脚本)、作为参数提供给 -c 调用选项的字符串(请参阅调用 Bash)或从用户终端读取其输入。
- 将输入分解为单词和运算符,遵守 Quoting 中描述的引用规则。这些标记由元字符分隔。这一步执行别名扩展(请参阅别名)。
- 将标记解析为简单和复合命令(请参阅 Shell 命令)。
- 执行各种 shell 扩展(请参阅 Shell 扩展),将扩展的标记分解为文件名列表(请参阅文件名扩展)以及命令和参数。
- 执行任何必要的重定向(请参阅重定向)并从参数列表中删除重定向运算符及其操作数。
- 执行命令(请参阅执行命令)。
- 可选择等待命令完成并收集其退出状态(请参阅退出状态)。
What's happening here is that builtins don't get their own execution environment, so they never see the modified environment. In addition, simple commands (e.g. /bin/echo) doget a modified ennvironment (which is why the env example worked) but the shell expansion is taking place in the currentenvironment in step #4.
这里发生的事情是内置程序没有自己的执行环境,所以他们永远不会看到修改后的环境。此外,简单的命令(例如 /bin/echo)确实会获得修改后的环境(这就是 env 示例起作用的原因),但 shell 扩展正在第 4 步中的当前环境中进行。
In other words, you aren't passing 'aaa $TESTVAR ccc' to /bin/echo; you are passing the interpolated string (as expanded in the current environment) to /bin/echo. In this case, since the current environment has no TESTVAR, you are simply passing 'aaa ccc' to the command.
换句话说,您没有将 'aaa $TESTVAR ccc' 传递给 /bin/echo;您将插入的字符串(在当前环境中展开)传递给 /bin/echo。在这种情况下,由于当前环境没有TESTVAR,您只需将 'aaa ccc' 传递给命令。
Summary
概括
The documentation could be a lot clearer. Good thing there's Stack Overflow!
文档可能会更清楚。好消息是堆栈溢出!
See Also
也可以看看
http://www.gnu.org/software/bash/manual/bashref.html#Command-Execution-Environment
http://www.gnu.org/software/bash/manual/bashref.html#Command-Execution-Environment
回答by Markus Kuhn
To achieve what you want, use
要实现您想要的,请使用
( SOMEVAR=BBB; echo zzz $SOMEVAR zzz )
Reason:
原因:
You must separate the assignment by semicolon or new line from the next command, otherwise it is not executed before parameter expansionhappens for the next command (echo).
You need to make the assignment inside a subshellenvironment, to make sure it does not persist beyond the current line.
必须用分号或新行将赋值与下一个命令分开,否则在下一个命令(echo)的参数扩展发生之前不会执行它。
您需要在subshell环境中进行分配,以确保它不会在当前行之外持续存在。
This solution is shorter, neater and more efficient than some of the others suggested, in particular it does not create a new process.
该解决方案比其他一些建议的解决方案更短、更简洁、更高效,特别是它不会创建新流程。
回答by FatalError
The reason is that this sets an environment variable for one line. But, echo
does not do the expansion, bash
does. Hence, your variable is actually expanded before the command is executed, even though SOME_VAR
is BBB
in the context of the echo command.
原因是这为一行设置了一个环境变量。但是,echo
不做扩展,bash
做。因此,您的变量实际上是扩大了执行命令之前,即使SOME_VAR
是BBB
在echo命令的情况下。
To see the effect, you can do something like:
要查看效果,您可以执行以下操作:
$ SOME_VAR=BBB bash -c 'echo $SOME_VAR'
BBB
Here the variable is not expanded until the child process executes, so you see the updated value. if you check SOME_VARIABLE
again in the parent shell, it's still AAA
, as expected.
此处变量在子进程执行之前不会扩展,因此您会看到更新后的值。如果您SOME_VARIABLE
再次检查父 shell,它仍然是AAA
,正如预期的那样。
回答by Kyros
SOMEVAR=BBB; echo zzz $SOMEVAR zzz
Use a ; to separate statements that are on the same line.
用一个 ; 分隔同一行的语句。
回答by brian
Here's one alternative:
这是一种选择:
SOMEVAR=BBB && echo zzz $SOMEVAR zzz