Bash:在命令行中指定回显的环境variables?
考虑这个片段:
$ SOMEVAR=AAA $ echo zzz $SOMEVAR zzz zzz AAA zzz
在这里我已经在第一行设置了$SOMEVAR
到AAA
,当我在第二行回显它时,我得到了预期的AAA
内容。
但是,如果我尝试在echo
的同一个命令行上指定variables:
$ SOMEVAR=BBB echo zzz $SOMEVAR zzz zzz AAA zzz
…我没有像预期的那样得到BBB
– 我得到了旧的价值( AAA
)。
这是事情应该如何? 如果是这样,那么你怎么能指定像LD_PRELOAD=/... program args ...
variablesLD_PRELOAD=/... program args ...
并有它的工作? 我错过了什么?
你看到的是预期的行为。 麻烦的是父shell在命令行上使用修改后的环境调用命令之前先评估$SOMEVAR
。 您需要将$SOMEVAR
的评估推迟到设置环境之后。
您的直接选项包括:
-
SOMEVAR=BBB eval echo zzz '$SOMEVAR' zzz
。 -
SOMEVAR=BBB sh -c 'echo zzz $SOMEVAR zzz'
。
这两个使用单引号来防止父shell评估$SOMEVAR
; 只有在环境中设置后才能评估(在单个命令期间临时)。
另一种select是使用子壳符号(也是Marcus Kuhn在他的回答中提出的 ):
(SOMEVAR=BBB; echo zzz $SOMEVAR zzz)
该variables仅在子shell中设置
这个问题,重新审视
坦率地说,手册在这一点上令人困惑。 GNU Bash手册说:
任何简单的命令或函数的环境(注意这不包括内build函数)可以通过在参数赋值前加前缀来临时扩充,如Shell参数中所述。 这些赋值语句只影响该命令看到的环境。
如果你真的parsing这个句子,那么它所说的是命令/函数的环境被修改了,而不是父进程的环境。 所以,这将工作:
$ TESTVAR=bbb env | fgrep TESTVAR TESTVAR=bbb
因为env命令的环境在执行之前已被修改。 但是,这不起作用:
$ set -x; TESTVAR=bbb echo aaa $TESTVAR ccc + TESTVAR=bbb + echo aaa ccc aaa ccc
因为参数扩展是由shell执行的。
口译员的步骤
问题的另一个部分是Bash为解释者定义了这些步骤 :
- 从作为参数提供的string(参见调用Bash)或从用户的terminal读取文件的input(请参阅Shell脚本)。
- 将input分解为单词和操作符,遵守引用中所述的引用规则。 这些令牌由元字符分隔。 别名扩展是通过此步骤执行的(请参见别名)。
- 将令牌parsing为简单和复合命令(请参阅Shell命令)。
- 执行各种shell扩展(请参阅Shell Expansions),将扩展令牌拆分为文件名列表(请参阅文件名扩展)以及命令和参数。
- 执行任何必要的redirect(请参阅redirect),并从参数列表中删除redirect运算符及其操作数。
- 执行命令(请参阅执行命令)。
- (可选)等待命令完成并收集其退出状态(请参阅退出状态)。
这里发生的事情是,builtins没有得到自己的执行环境,所以他们从来没有看到修改过的环境。 另外,简单的命令(比如/ bin / echo) 确实得到了一个修改后的环境(这就是为什么env例子工作的原因),但是在步骤#4中, 当前环境正在发生shell扩展。
换句话说,你没有将“aaa $ TESTVAR ccc”传递给/ bin / echo; 您正在将插入的string(在当前环境中展开)传递给/ bin / echo。 在这种情况下,由于当前环境没有TESTVAR ,因此只需将“aaa ccc”传递给命令即可。
概要
文件可以更清晰。 好东西有堆栈溢出!
也可以看看
http://www.gnu.org/software/bash/manual/bashref.html#Command-Execution-Environment
为了达到你想要的,使用
( SOMEVAR=BBB; echo zzz $SOMEVAR zzz )
原因:
-
您必须用分号或新行分隔下一个命令的分配,否则在下一个命令(回声)发生参数扩展之前不执行分配。
-
您需要在子环境中进行分配,以确保它不会超出当前行。
这个解决scheme比别人build议的更短,更整洁,更高效,特别是它不会创build一个新的stream程。
原因是这为一行设置了一个环境variables。 但是, echo
不做扩展, bash
的确如此。 因此,即使在echo命令的上下文中SOME_VAR
是BBB
,您的variables实际上在命令执行之前也会SOME_VAR
。
要看到效果,你可以做一些事情:
$ SOME_VAR=BBB bash -c 'echo $SOME_VAR' BBB
这里variables不会被扩展,直到subprocess执行,所以你看到更新的值。 如果您在父shell中再次检查SOME_VARIABLE
,它仍然是AAA
,如预期的那样。
SOMEVAR=BBB; echo zzz $SOMEVAR zzz
用一个 ; 分隔在同一行上的语句。
这里有一个select:
SOMEVAR=BBB && echo zzz $SOMEVAR zzz