一个 while 循环和一个 here-document - 什么时候发生?

use*_*970 8 text-processing control-flow here-document variable read

我有这个 while 循环和 here-document 组合,我在 Bash 4.3.48(1) 中运行,我根本不明白它的逻辑。

while read file; do source ~/unwe/"$file"
done <<-EOF
    x.sh
    y.sh
EOF
Run Code Online (Sandbox Code Playgroud)

我的问题由以下部分组成:

  1. read这里做什么(我总是read用来声明一个变量并以交互方式分配它的值,但我错过了它应该在这里做什么)。

  2. 是什么意思while readwhile进来的概念从哪里来?

  3. 如果 here-document 本身出现循环之后,它甚至如何受到循环的影响?我的意思是,它出现在 之后done,而不是在循环内部,那么这两个结构之间的实际关联是什么?

  4. 为什么这会失败?

    while read file; do source ~/unwe/"$file" done <<-EOF
        x.sh
        y.sh
    EOF
    
    Run Code Online (Sandbox Code Playgroud)

    我的意思是,donedone...那么为什么done <<-EOF与循环在同一行上很重要?如果我没记错的话,我确实遇到过这样一种情况,其中for循环是单行的并且仍然有效。

Kus*_*nda 13

  1. read命令从其标准输入流中读取并将读取的内容分配给变量file(它比这更复杂,请参阅此处的详细讨论)。标准输入流来自 here-document 之后重定向到循环中done。如果没有从任何地方提供数据,它将以交互方式从终端读取。但在这种情况下,shell 已安排将其输入流连接到 here-document。

  2. while read将导致循环迭代,直到read命令返回非零退出状态。如果有任何错误,或者(最常见)没有更多数据可供读取(其输入流处于文件结束状态),就会发生这种情况。

    约定是,任何希望向调用 shell 发出错误或“假”或“否”信号的实用程序都通过返回非零退出状态来实现。零退出状态表示“真”或“是”或“无错误”。此状态,您是否希望检查它,在$?(仅从上次执行的实用程序中)可用。退出状态可用于if语句和while循环或任何需要测试的地方。例如

    if grep -q 'pattern' file; then ...; fi
    
    Run Code Online (Sandbox Code Playgroud)
  3. here-document 是重定向的一种形式。在这种情况下,它是重定向到循环中。循环内的任何内容都可以从中读取,但在这种情况下,只有read命令才能读取。请仔细阅读此处的文档。如果输入来自一个普通文件,最后一行应该是

    done <filename
    
    Run Code Online (Sandbox Code Playgroud)

    将循环视为一个命令可能会使这更直观:

    while ...; do ...; done <filename
    
    Run Code Online (Sandbox Code Playgroud)

    这是一种情况

    somecommand <filename
    
    Run Code Online (Sandbox Code Playgroud)

    一些 shell 还支持“here-strings” <<<"string"

    cat <<<"This is the here-string"
    
    Run Code Online (Sandbox Code Playgroud)

    DavidFoerster指出,如果任何两个脚本x.sh,并y.sh从标准输入读取,但没有明确报错数据从文件或从其他地方读取,读取的数据实际上会从这里文档。

    如果 ax.sh只包含read a,这将使变量a包含字符串y.sh,并且y.sh脚本永远不会运行。这是因为标准输入被重定向到循环中的所有命令while(并且还被任何调用的脚本或命令“继承”),并且第二行在循环可以读取x.sh之前被“消耗” 。whileread

    如果这种行为是不需要的,则可以避免,但有点棘手

  4. 它失败是因为;之前没有或换行符done;之前没有或换行done,单词done将被视为 的参数source,并且循环也不会正确关闭(这是一个语法错误)。

    any 几乎;可以用换行符替换(至少当它是命令分隔符时)。它标志着一个命令的结尾,一样|&&&||(也可能是别人,我已经忘记了)。

  • +1 和一个挑剔:“循环中的任何内容都可以从中读取,但在这种情况下,只有 `read` 命令可以读取。” – 任何或所有来源的 shell 脚本(及其递归调用的命令)都可以从标准输入中读取并更改循环调用。 (3认同)