Bash:在命令行中指定回显的环境variables?

考虑这个片段:

$ SOMEVAR=AAA $ echo zzz $SOMEVAR zzz zzz AAA zzz 

在这里我已经在第一行设置了$SOMEVARAAA ,当我在第二行回显它时,我得到了预期的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的评估推迟到设置环境之后。

您的直接选项包括:

  1. SOMEVAR=BBB eval echo zzz '$SOMEVAR' zzz
  2. 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为解释者定义了这些步骤 :

  1. 从作为参数提供的string(参见调用Bash)或从用户的terminal读取文件的input(请参阅Shell脚本)。
  2. 将input分解为单词和操作符,遵守引用中所述的引用规则。 这些令牌由元字符分隔。 别名扩展是通过此步骤执行的(请参见别名)。
  3. 将令牌parsing为简单和复合命令(请参阅Shell命令)。
  4. 执行各种shell扩展(请参阅Shell Expansions),将扩展令牌拆分为文件名列表(请参阅文件名扩展)以及命令和参数。
  5. 执行任何必要的redirect(请参阅redirect),并从参数列表中删除redirect运算符及其操作数。
  6. 执行命令(请参阅执行命令)。
  7. (可选)等待命令完成并收集其退出状态(请参阅退出状态)。

这里发生的事情是,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_VARBBB ,您的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