eval命令在循环内不起作用

时间:2017-02-07 06:32:48

标签: bash shell eval

如果我有一个简单的bash脚本set_token.sh

#!/bin/bash

output='export AWS_ACCESS_KEY_ID="111"
export AWS_SECRET_ACCESS_KEY="222"
export AWS_SESSION_TOKEN="333"'

echo "$output" | while read line; do eval $line; done

已执行set_token.sh未成功设置3个环境变量。但是,如果我分别在每一行上运行eval,它就会起作用。

$ eval 'export AWS_ACCESS_KEY_ID="111"'
$ eval 'export AWS_SECRET_ACCESS_KEY="222"'
$ eval 'export AWS_SESSION_TOKEN="333"'

为什么会这样?

3 个答案:

答案 0 :(得分:3)

您可以在没有循环且没有eval的情况下实现所需的结果。

source <(echo "$output")

<()构造是一个过程替换。它执行内部命令,创建一个FIFO(特殊的先进先出文件),然后转换为source可以读取的实际文件路径(指向FIFO)。

当然,您也可以将实际作业存储在一个文件中,而不是将它们放在output变量中。

source config_file

source命令(或其更标准的形式.)从文件中读取命令并在当前shell中执行它们,而不启动单独的进程或子shell,因此源文件中的变量赋值可以正常工作。对配置文件有用,但当然你必须确保没有人可以在这些文件中放置任意命令,因为这会带来安全风险。

重要

如果您想在脚本中添加声明(在您的情况下为set_token.sh),则必须必须来源此脚本(即使用source.执行),不是用bash执行或直接调用它(如果它是可执行的)。除source.之外的任何方法都将启动子进程,并且子进程无法分配之后父进程可见的变量。采购不会创建单独的流程,这就是分配工作的原因。 export关键字只会使子项处理可以看到作业,它们无法使作业对父作业可见。

答案 1 :(得分:1)

在这种情况下,不确定为什么要使用eval。为什么不直接设置变量如下:

export AWS_ACCESS_KEY_ID="111"
export AWS_SECRET_ACCESS_KEY="222"
export AWS_SESSION_TOKEN="333"

你的循环在子shell中运行(因为echo "$output" | ...),这就是你的变量在外面可见的原因。并不是eval不起作用!别担心 - 这种情况发生在很多人身上。

如果您坚持使用循环和eval,则可以使用流程替换< <(command)

while read line; do eval $line; done < <(printf "%s\n" "$output")

答案 2 :(得分:0)

Fred's helpful answer包含一个可行的解决方案和好的指针(Bash FAQ #24 - "I set variables in a loop that's in a pipeline. Why do they disappear after the loop terminates?"中解释了原始方法的问题)。

也就是说,在您的具体情况下 - 假设您愿意接受使用eval的风险 - 您可以将直接应用于您的多行字符串:< / p>

#!/bin/bash

output='export AWS_ACCESS_KEY_ID="111"
export AWS_SECRET_ACCESS_KEY="222"
export AWS_SESSION_TOKEN="333"'

# This defines all 3 AWS_* environment variables.
eval "$output"

重申Fred的观点:要使环境变量在当前 shell中生效,您必须 source 脚本(使用内置{{1} }或其(有效)别名.):

source