如果我运行

export TEST=foo
echo $TEST


它输出foo。

如果我运行

TEST=foo echo $TEST


/>没有。如何在不使用导出或脚本的情况下获得此功能?

评论

小心一点,这个故事比最初出现的更多。我邀请您检查我的答案。

#1 楼

这是因为shell在实际运行命令之前在命令行中扩展了该变量,而那时该变量不存在。如果使用

TEST=foo; echo $TEST


它将起作用。

export将使变量出现在随后执行的命令的环境中(有关此在bash中工作,请参阅help export)。如果只需要变量出现在一个命令的环境中,请使用您尝试过的方法,即:

TEST=foo your-application


评论


/ usr / bin / env呢?那也不行,你知道为什么吗?

– Benubird
2014年7月9日在16:43

相同的原因-shell在执行命令行之前扩展$ TEST。运行echo后(还要注意echo通常会转换为shell内置命令而不是/ bin / echo),它会在其环境中看到设置的变量。但是,echo $ TEST不会告诉echo从其环境中输出变量TEST的内容。它告诉外壳程序运行echo,并且参数是TEST变量中当前存在的参数-这是两个非常不同的东西。

–彼得
2014年7月9日17:41

@peterph如果shell在实际运行命令之前在命令行中扩展了变量,那么为什么不在var = value sh -c'echo“ $ var”'中将其扩展呢?

–架子
18年3月12日在21:56

正如我在这里向您解释的:这是因为变量在双引号内(例如,“…$ var…”)而不是在单引号内(例如,“…$ var…”)扩展。由于echo“ $ var”在单引号内,因此整个字符串将传递到新(sh-c)外壳,而无需由外部交互式外壳解释。 …(续)

– G-Man说“恢复莫妮卡”
18年3月14日在20:21

(续)…正如igal昨天所说,有两轮解析-尽管我相信igal会误读您的问题。除了由父shell进行的解析外,没有两轮解析。进行两轮解析-一轮由外部交互(父)外壳完成,而一轮由新的(sh-c)子外壳完成。

– G-Man说“恢复莫妮卡”
18年3月14日在20:21

#2 楼

我怀疑您想让shell变量具有有限的作用域,而不是环境变量。环境变量是执行时传递给命令的字符串的列表。



var=value echo whatever


您要将var=value字符串传递给回声接收的环境。但是,echo对其环境列表¹并没有执行任何操作,并且无论如何在大多数shell中,echo都是内置的,因此无法执行。

如果您编写了

var=value sh -c 'echo "$var"'


那将是另一回事。在这里,我们将var=value传递给sh命令,而sh确实使用了它的环境。 Shell将它们从其环境接收的每个变量转换为Shell变量,因此var环境变量sh接收的将转换为$var变量,并且在该echo命令行中对其进行扩展时,它将变为echo value。由于默认情况下环境是继承的,因此echo还将在其环境中接收var=value(或者如果执行了该环境),但是echo不再关心该环境。

现在,如果我这样怀疑,您想要限制外壳变量的范围,有几种可能的方法。

便携式(Bourne和POSIX):

(var=value; echo "1: $var"); echo "2: $var"


上面的(...)启动了一个子外壳(大多数外壳中都有一个新的外壳过程),因此在那里声明的任何变量都只会影响该子外壳,因此我希望上面的代码输出“ 1:值”和“ 2:”或“ 2:what-var-was-set-before”。

对于大多数类似Bourne的shell,您可以使用函数和内置的“ local”:

f() {
  local var
  var=value
  echo "1: $var"
}
f
echo "2: $var"


通过zsh,可以使用内联函数:

(){ local var=value; echo "1: $var"; }; echo "2: $var"


或:

function { local var=value; echo "1: $var"; }; echo "2: $var"


使用bash和zsh(但不适用于ash,pdksh或AT&T ksh),此技巧也适用:

var=value eval 'echo "1: $var"'; echo "2: $var"


一个可以在更多shell中使用的变体(dashmkshyash),但不能在zsh中使用(除非在sh / ksh仿真中有效):

var=value command eval 'echo "1: $var"'; echo "2: $var"


(在前面使用command POSIX shell中特殊的内置函数(此处为eval)的使用消除了它们的特殊性(此处返回的变量分配在返回后仍然有效)。


¹完全正确。几种实现方式将关心本地化环境变量(LANGLOCPATHLC_* ...),GNU实现则关心POSIXLY_CORRECT环境变量(将env echo --versionPOSIXLY_CORRECT=1 env echo --version在GNU系统上进行比较)。

评论


对我而言,这是正确的解决方案。我不希望变量'var'像接受的答案那样污染环境。

– kronenpj
17年9月13日在15:12

#3 楼

您做得正确,但是bash语法很容易被误解:您可能认为echo $TEST导致echo提取TEST env var然后打印出来,但事实并非如此。因此,给定

export TEST=123


然后

TEST=456 echo $TEST


涉及以下顺序:



Shell解析整个命令行并执行所有变量替换,因此命令行变为

TEST=456 echo 123



它创建了temp vars在命令之前设置,因此它保存TEST的当前值并用456覆盖;现在,命令行为

echo 123


它执行剩余的命令,在这种情况下将123打印到stdout(因此,剩下的shell命令甚至没有使用temp值代表TEST的值)
它恢复TEST的值

而是使用printenv,因为它不涉及变量替换:

>> export TEST=123
>> printenv TEST
123
>> TEST=456 printenv TEST
456
>> printenv TEST && TEST=456 printenv TEST && TEST=789 printenv TEST && printenv TEST
123
456
789
123
>>


评论


+1我发现printenv有助于测试/概念验证(行为类似于脚本,而不是echo)

–达里恩
19年1月7日在8:28

#4 楼

您可以使用以下方法来工作:

TEST=foo && echo $TEST


评论


在这种情况下,TEST = foo作为单独的语句运行-它不仅在echo上下文中设置。

– codeforester
17年1月3日,19:54