Bash:在命令行上指定echo的环境变量?

时间:2012-06-07 19:20:26

标签: bash environment-variables echo

请考虑以下代码段:

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

我在第一行将$SOMEVAR设置为AAA - 当我在第二行回显它时,我按预期获得AAA个内容。

但是,如果我尝试在与echo相同的命令行上指定变量:

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

...我没有按照预期得到BBB - 我得到旧值(AAA)。

这是怎么回事?如果是这样,那么为什么你可以指定像LD_PRELOAD=/... program args ...这样的变量并让它工作?我错过了什么?

6 个答案:

答案 0 :(得分:87)

您看到的是预期的行为。问题是父shell在调用具有修改环境的命令之前在命令行上评估$SOMEVAR。在设置环境之前,您需要延迟$SOMEVAR的评估。

您的直接选择包括:

  1. SOMEVAR=BBB eval echo zzz '$SOMEVAR' zzz
  2. SOMEVAR=BBB sh -c 'echo zzz $SOMEVAR zzz'
  3. 这两个都使用单引号来阻止父shell评估$SOMEVAR;它仅在环境中设置后进行评估(暂时,在单个命令的持续时间内)。

    另一种选择是使用子shell表示法(Marcus Kuhnanswer建议):

    (SOMEVAR=BBB; echo zzz $SOMEVAR zzz)
    

    该变量仅在子shell中设置

答案 1 :(得分:33)

问题,重访

坦率地说,手册在这一点上令人困惑。 GNU Bash manual说:

  

任何简单命令或函数的环境[请注意,这不包括内置]可以通过在参数赋值前添加前缀来临时扩充,如Shell参数中所述。这些赋值语句仅影响该命令所见的环境。

如果您真的解析了句子,那么它所说的是命令/功能的环境被修改,而不是父进程的环境。所以,这将有效:

$ 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 defines these steps为其解释器:

  1. 从字符串中读取文件中的输入(请参阅Shell Scripts) 作为-c调用选项的参数提供(请参阅调用 Bash),或来自用户的终端。
  2. 将输入分解为单词和运算符,遵守引用规则 在引用中描述。这些令牌由元字符分隔。 别名扩展由此步骤执行(请参阅别名)。
  3. 将标记解析为简单和复合命令(请参阅Shell命令)。
  4. 执行各种shell扩展(请参阅Shell扩展), 将扩展的标记分解为文件名列表(请参阅文件名 扩展)和命令和参数。
  5. 执行任何必要的重定向(请参阅重定向)并删除 重定向运算符及其参数列表中的操作数。
  6. 执行命令(请参阅执行命令)。
  7. (可选)等待命令完成并收集其退出 状态(请参阅退出状态)。
  8. 这里发生的事情是内置程序没有自己的执行环境,因此它们永远不会看到修改后的环境。此外,简单命令(例如/ bin / echo)获得修改的环境(这就是env示例有效的原因)但是shell扩展发生在当前中步骤#4中的环境。

    换句话说,你没有将'aaa $ TESTVAR ccc'传递给/ bin / echo;您正在将插值字符串(在当前环境中展开)传递给/ bin / echo。在这种情况下,由于当前环境没有 TESTVAR ,您只需将'aaa ccc'传递给命令。

    摘要

    文档可能更清晰。好事就是堆栈溢出!

    另请参阅

    http://www.gnu.org/software/bash/manual/bashref.html#Command-Execution-Environment

答案 2 :(得分:19)

要实现您的目标,请使用

( SOMEVAR=BBB; echo zzz $SOMEVAR zzz )

原因:

  • 您必须使用分号或新行与下一个命令分隔分配,否则在下一个命令(echo)发生参数扩展之前不会执行该分配。

    < / LI>
  • 您需要在子shell 环境中进行分配,以确保它不会超出当前行。

此解决方案比其他一些解决方案更短,更整洁,更高效,特别是它不会创建新流程。

答案 3 :(得分:10)

原因是这为一行设置了一个环境变量。但是,echo不会进行扩展,bash会进行扩展。因此,即使在echo命令的上下文中SOME_VARBBB,您的变量实际上也会在命令执行之前展开。

要查看效果,您可以执行以下操作:

$ SOME_VAR=BBB bash -c 'echo $SOME_VAR'
BBB

此处变量在子进程执行之前不会展开,因此您会看到更新的值。如果你在父shell中再次检查SOME_VARIABLE,它仍然是AAA,正如预期的那样。

答案 4 :(得分:1)

SOMEVAR=BBB; echo zzz $SOMEVAR zzz

使用;分隔同一行的陈述。

答案 5 :(得分:1)

以下是另一种选择:

SOMEVAR=BBB && echo zzz $SOMEVAR zzz