从多行Here Document中读取Bash变量

时间:2013-03-14 22:22:27

标签: bash

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

看看我的做法如何具有将1作为$?返回的副作用...


Bash代码:

#!/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 个答案:

答案 0 :(得分: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。

答案 1 :(得分:3)

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

read -r -d $'\3' variable <<<"thud\nthud\n"$'\3' ; echo $?
然而,那说,在heredoc中这很难做到。

答案 2 :(得分: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'

退出状态为1的原因已由Sorpigal提供..

答案 3 :(得分:3)

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

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

有点相关: