2

从 Bash 中的 Here Document 读取多行变量的完美方法是什么?

看看我的做法是如何产生返回的1副作用$?......


巴什代码:

#!/bin/bash

printf "Unsetting...\n"
unset variable
printf "Exit status: %s.\n" "$?"
printf "Variable: %s.\n" "${variable}"

printf "\n"

printf "Setting to 'foo'...\n"
variable='foo'
printf "Exit status: %s.\n" "$?"
printf "Variable: %s.\n" "${variable}"

printf "\n"

printf "Setting to 'bar' by reading stdin from process substitution...\n"
read variable < <(echo 'bar')
printf "Exit status: %s.\n" "$?"
printf "Variable: %s.\n" "${variable}"

printf "\n"

printf "Setting to 'baz' by reading stdin from Here String...\n"
here_string='baz'
read variable <<< "${here_string}"
printf "Exit status: %s.\n" "$?"
printf "Variable: %s.\n" "${variable}"

printf "\n"

printf "Setting to 'quux' by reading stdin from Here Document...\n"
read variable <<- 'EOF'
quux
EOF
printf "Exit status: %s.\n" "$?"
printf "Variable: %s.\n" "${variable}"

printf "\n"

printf "Setting to 'thud <newline> thud' by reading stdin from Here Document...\n"
read -d '' variable <<- 'EOF'
thud
thud
EOF
printf "Exit status: %s.\n" "$?" # ONE?!one!!oneone? :)
printf "Variable: %s.\n" "${variable}"

输出

Unsetting...
Exit status: 0.
Variable: .

Setting to 'foo'...
Exit status: 0.
Variable: foo.

Setting to 'bar' by reading stdin from process substitution...
Exit status: 0.
Variable: bar.

Setting to 'baz' by reading stdin from Here String...
Exit status: 0.
Variable: baz.

Setting to 'quux' by reading stdin from Here Document...
Exit status: 0.
Variable: quux.

Setting to 'thud <newline> thud' by reading stdin from Here
Document...
Exit status: 1.
Variable: thud
thud.
4

4 回答 4

4

我认为问题在于read在看到 ASCII NUL 字符之前看到文件结尾。但是,如果这是真的,以下应该以 0 退出:

read -d '' variable <<< $'thud\nthud\x00'

但事实并非如此。

代替真正的修复,我可以提供以下技巧。由于它会阻止任何命令实际返回 0,因此它不应破坏您的登录脚本:

read -d '' variable <<-'EOF' || true
thud
thud
EOF

read仍然退出 1,但这只会导致 shell 执行true命令,保证退出 0。

于 2013-03-14T22:42:11.610 回答
4

read到达 EOF 时返回 1,同时分配读取的最后一个结果。这就是为什么不以换行符结尾的文件有问题的原因,因为一个简单read的循环不会为最后一行运行循环体。

当你在read -d ''没有将 NUL 字节放入输入的情况下使用时,这就像读取文件的最后一行一样。问题是为什么read在这种情况下你会想要返回 0?它正在做它应该做的事情。另请注意,heredocs(和 herestrings)总是自动在末尾添加换行符。

有点相关:

于 2013-03-14T23:33:43.173 回答
3

read如果它到达文件末尾而没有击中其分隔符,将返回非零值。显然 \0 被视为EOF,无论它是否是您的分隔符。防止这种情况的一个技巧是选择一个不太可能的分隔符并在最后用它填充你的字符串。例子:

read -r -d $'\3' variable <<<"thud\nthud\n"$'\3' ; echo $?

话虽如此,但这在heredoc中更难做到。

于 2013-03-14T22:55:12.153 回答
3

您可以将 here-document 读入带有mapfile或其别名的数组readarray

mapfile var <<-'EOF'
thud
thud
EOF

导致

var=([0]="thud
" [1]="thud
")

然后只是连接数组元素,例如

variable=${var[0]}
variable+=${var[1]}
...

对于可变长度的数组,您可以在循环中执行此操作或使用printf内置函数(感谢 eush77):

printf -v variable "%s" "${var[@]}"

两种选择都会导致

variable=$'thud\nthud\n'

Sorpigal 已经给出了退出状态为 1 的原因..

于 2013-03-14T23:12:31.467 回答