【问题标题】:Why are heredoc redirections not allowed before a while loop为什么在while循环之前不允许heredoc重定向
【发布时间】:2019-01-07 18:16:51
【问题描述】:

背景

POSIX Shell 命令语言允许重定向遵循 compound 命令。 standard 说(强调我的)

2.9.4 复合命令

shell 有几个编程结构,它们是“复合命令”,它们为命令提供控制流。这些复合命令中的每一个在开头都有一个保留字或控制运算符,在末尾有一个相应的终止符保留字或运算符。此外,每个都可以跟在与终止符相同的行上的重定向。每个重定向都应适用于复合命令中未明确覆盖该重定向的所有命令。

出于美学原因,我想在我的while循环之前放置一个heredoc

<<'RECORDS' while
foo:bar
baz:quux
...
RECORDS
   IFS=: read -r A B
do
  # do something with A and B
done

因为它使代码更容易理解。但是,它在我尝试过的 shell 中不起作用(bashdash)。我收到错误提示找不到“while”命令,我认为这意味着在领先的 heredoc 之后需要一个 simple 命令而不是 compound 命令。

我无法将heredoc 移动到read 之后,因为它会在每次迭代时从新的heredoc 中读取第一行。我知道我可以通过将heredoc 移到done 之后来解决这个问题。我还可以在循环之前使用exec 打开一个指向heredoc 的fd,并添加一个到read 的重定向。

我的问题

在复合命令之前不能发生重定向的原因是什么?由于 POSIX 没有明确禁止,是否有支持它的 shell?

【问题讨论】:

  • “它使代码更容易理解”。这是主观的,充其量是。
  • @chepner 确实!这就是我提出这个问题的原因,但我要求澄清这个看似任意的 shell 限制。
  • 有时基本原理只是现有行为。如果大多数现有的 shell 实现在复合命令之前禁止重定向,则规范没有理由强制执行新行为。 (我不知道真正的原因,因此发表了此评论。也许有技术原因导致解析此类结构非常困难,尽管我无法想象它会比解析实际语法困难得多。)

标签: shell while-loop sh posix heredoc


【解决方案1】:

Z shell (zsh) 将接受这种非标准语法。 POSIX 标准化了现有的实践,对于 shell,参考实现是 Korn shell(ksh88,或者只是 ksh)。由于该实现仅支持遵循标准化复合语句的重定向。

您可以通过多种方式以更便携(也更易于阅读)的形式编写循环。例如:

while
  IFS=: read -r A B
do
    echo $A $B
done <<'RECORDS'
foo:bar
baz:quux
RECORDS

是我做这种事情的最常见方式。或者您可以将循环包装在一个函数中并将输入重定向到该函数:

loop()
{
    while
      IFS=: read -r A B
    do
        echo $A $B
    done
}

<<'RECORDS' loop
foo:bar
baz:quux
RECORDS

这允许您在数据中混合对函数的调用,就像您最初想要的那样(我仍然不明白为什么您认为这更清楚:-)) 这两种技术都适用于bashdashkshksh93yashzsh

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-07-22
    • 1970-01-01
    • 2012-10-01
    • 1970-01-01
    • 1970-01-01
    • 2016-06-01
    • 1970-01-01
    • 2022-12-12
    相关资源
    最近更新 更多