【问题标题】:Why can't I eval inside a while loop?为什么我不能在 while 循环中进行评估?
【发布时间】:2012-08-23 06:07:02
【问题描述】:

我想在循环从命令中读取行的循环中创建 bash 别名。为了逐行读取输出,我相信我需要将输出通过管道传输到read。但是,当我这样做时,别名不存在。

如果我在.bashrc 中包含以下内容:

for x in a1 a2; do
    eval "alias $x='echo foo'"
done

echo -e "a3\na4" | while read x; do
    eval "alias $x='echo foo'"
done

别名 a1a2 存在,但 a3a4 不存在。这两个循环有什么区别?

【问题讨论】:

  • 这是在管道到while 循环时非常常见的问题。有关详细信息和各种替代解决方案,请参阅 this answerBashFAQ/024
  • 另外,这里没有必要使用evalalias $x='echo foo' 将在定义别名之前扩展 $x

标签: bash shell


【解决方案1】:

在 bash 4.2 及更高版本中,您可以设置 lastpipe 选项以防止管道的 last 命令在子 shell 中执行。作业控制也必须关闭 (set +m) 才能正常工作。

shopt -s lastpipe
set +m
echo -e "a3\na4" | while read x; do
    alias $x='echo foo'
done

【讨论】:

    【解决方案2】:

    管道中的 while 循环在子 shell 中运行。你可以这样做:

    while read x; do
        eval "alias $x='echo foo'"
    done << EOF
    a3
    a4 
    EOF
    

    【讨论】:

      【解决方案3】:

      问题在于管道。在a | b | c 形式的管道中,每个单独的命令abc 在单独的子shell [ref] 中运行,这意味着它接收到父执行的副本环境(包括别名),并且它对自己的副本所做的任何更改(例如通过运行 alias)都不会影响父级 [ref]。

      在您的情况下,您可以通过以下方式解决此问题:

      while read x; do
          eval "alias $x='echo foo'"
      done < <(echo -e "a3\na4")
      

      它仍将在子 shell 中运行 echo -e "a3\na4",但将在正常/父执行环境中运行 while-loop。

      【讨论】:

      • 我之前没见过&lt;(command) 语法。这是创建一个指向command 输出的文件描述符吗?
      • @JeffKlukas:是的;它被称为“进程替换”(参见gnu.org/software/bash/manual/bashref.html#Process-Substitution),它使用FIFO 或/dev/fd 文件。该文档暗示它不适用于所有系统,但它适用于我尝试过的所有系统,包括 Cygwin。
      猜你喜欢
      • 1970-01-01
      • 2022-10-16
      • 2019-05-10
      • 2022-01-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-03-05
      • 2018-03-07
      相关资源
      最近更新 更多