Bash 读取函数 returns 使用换行符时的错误代码
Bash read function returns error code when using new line delimiter
我有一个脚本,我正在 return 从中获取多个值,每个值占一行。为了将这些值捕获为 bash 变量,我使用了 read
内置函数(推荐 here)。
问题是,当我使用换行符作为 read
的分隔符时,我似乎总是得到一个非零退出代码。这对我的其余脚本造成了严重破坏,这些脚本检查操作的结果。
这是我正在做的事情的精简版:
$ read -d '\n' a b c < <(echo -e "1\n2\n3"); echo $?; echo $a $b $c
1
1 2 3
注意1的退出状态。
我不想重写我的脚本(上面的 echo
命令)以使用不同的分隔符(因为在代码的其他地方使用新行是有意义的)。
如何在成功读取 3 个值时让 read
正常运行并 return 零退出状态?
更新
嗯,看来我可能用错了 "delimiter"。来自手册页:
-d *delim*
The first character of delim is used to terminate the input line,
rather than newline.
因此,实现预期结果的一种方法是:
read -d '#' a b c < <(echo -e "1\n2\n3\n## END ##"); echo $?; echo $a $b $c
也许有更好的方法?
-d
在这里使用是错误的。您真正想要的是三个单独的读取调用:
{ read a; read b; read c; } < <(echo $'1\n2\n3\n')
确保输入以换行符结尾,以便最终 read
的退出状态为 0。
如果您事先不知道输入中有多少行,则需要将值读入数组。在 bash
4 中,只需调用一次 readarray
:
readarray -t arr < <(echo $'1\n2\n3\n')
在bash
4之前,需要使用循环:
while read value; do
arr+=("$value")
done < <(echo $'1\n2\n3\n')
read
总是读取一行输入; -d
选项改变了 read
对终止一行的想法。一个例子:
$ while read -d'#' value; do
> echo "$value"
> done << EOF
> a#b#c#
> EOF
a
b
c
这里的 "problem" 是 read
return 到达 EOF
时非零,这发生在分隔符不在输入末尾时.
因此,在您输入的末尾添加一个换行符将使其按您期望的方式工作(并将参数固定为 -d
,如 gniourf_gniourf 的评论中所示)。
您的示例中发生的事情是 read
正在扫描 \
并在找到它之前点击 EOF
。然后输入行在 \n
上被拆分(因为 IFS
)并分配给 $a
、$b
和 $c
。那么 read
是 returning 非零。
为此使用 -d
没问题,但 \n
是默认分隔符,因此如果您这样做并且 有 ,则不会更改任何内容得到正确的定界符 (-d $'\n'
) 首先你会看到你的例子根本不起作用(尽管它会 returned 0
from read)。 (参见 http://ideone.com/MWvgu7)
使用 read
时的一个常见习语(主要是 -d
的非标准值是测试 read
的 return 值 和分配给的变量是否有值。例如read -d '' line || [ "$line" ]
。即使在输入的最后一个"line"读取失败时也能正常工作,因为末尾缺少终止符。
因此,为了让您的示例正常工作,您需要按照 chepner 指示的方式使用多个 read
调用,或者(如果您真的想要一个调用)然后您想要(参见 http://ideone.com/xTL8Yn):
IFS=$'\n' read -d '' a b c < <(printf '1 1\n2 2\n3 3')
echo $?
printf '[%s]\n' "$a" "$b" "$c"
并将[=32=]
添加到输入流的末尾(例如printf '1 1\n2 2\n3 3[=33=]'
)或将|| [ "$a" ]
放在末尾将避免失败return来自read
呼叫.
读取IFS
的设置是为了防止shell在空格上进行分词并错误地分解我的输入。 -d ''
在 [=32=]
上 read
。
我有一个脚本,我正在 return 从中获取多个值,每个值占一行。为了将这些值捕获为 bash 变量,我使用了 read
内置函数(推荐 here)。
问题是,当我使用换行符作为 read
的分隔符时,我似乎总是得到一个非零退出代码。这对我的其余脚本造成了严重破坏,这些脚本检查操作的结果。
这是我正在做的事情的精简版:
$ read -d '\n' a b c < <(echo -e "1\n2\n3"); echo $?; echo $a $b $c
1
1 2 3
注意1的退出状态。
我不想重写我的脚本(上面的 echo
命令)以使用不同的分隔符(因为在代码的其他地方使用新行是有意义的)。
如何在成功读取 3 个值时让 read
正常运行并 return 零退出状态?
更新
嗯,看来我可能用错了 "delimiter"。来自手册页:
-d *delim* The first character of delim is used to terminate the input line, rather than newline.
因此,实现预期结果的一种方法是:
read -d '#' a b c < <(echo -e "1\n2\n3\n## END ##"); echo $?; echo $a $b $c
也许有更好的方法?
-d
在这里使用是错误的。您真正想要的是三个单独的读取调用:
{ read a; read b; read c; } < <(echo $'1\n2\n3\n')
确保输入以换行符结尾,以便最终 read
的退出状态为 0。
如果您事先不知道输入中有多少行,则需要将值读入数组。在 bash
4 中,只需调用一次 readarray
:
readarray -t arr < <(echo $'1\n2\n3\n')
在bash
4之前,需要使用循环:
while read value; do
arr+=("$value")
done < <(echo $'1\n2\n3\n')
read
总是读取一行输入; -d
选项改变了 read
对终止一行的想法。一个例子:
$ while read -d'#' value; do
> echo "$value"
> done << EOF
> a#b#c#
> EOF
a
b
c
这里的 "problem" 是 read
return 到达 EOF
时非零,这发生在分隔符不在输入末尾时.
因此,在您输入的末尾添加一个换行符将使其按您期望的方式工作(并将参数固定为 -d
,如 gniourf_gniourf 的评论中所示)。
您的示例中发生的事情是 read
正在扫描 \
并在找到它之前点击 EOF
。然后输入行在 \n
上被拆分(因为 IFS
)并分配给 $a
、$b
和 $c
。那么 read
是 returning 非零。
为此使用 -d
没问题,但 \n
是默认分隔符,因此如果您这样做并且 有 ,则不会更改任何内容得到正确的定界符 (-d $'\n'
) 首先你会看到你的例子根本不起作用(尽管它会 returned 0
from read)。 (参见 http://ideone.com/MWvgu7)
使用 read
时的一个常见习语(主要是 -d
的非标准值是测试 read
的 return 值 和分配给的变量是否有值。例如read -d '' line || [ "$line" ]
。即使在输入的最后一个"line"读取失败时也能正常工作,因为末尾缺少终止符。
因此,为了让您的示例正常工作,您需要按照 chepner 指示的方式使用多个 read
调用,或者(如果您真的想要一个调用)然后您想要(参见 http://ideone.com/xTL8Yn):
IFS=$'\n' read -d '' a b c < <(printf '1 1\n2 2\n3 3')
echo $?
printf '[%s]\n' "$a" "$b" "$c"
并将[=32=]
添加到输入流的末尾(例如printf '1 1\n2 2\n3 3[=33=]'
)或将|| [ "$a" ]
放在末尾将避免失败return来自read
呼叫.
读取IFS
的设置是为了防止shell在空格上进行分词并错误地分解我的输入。 -d ''
在 [=32=]
上 read
。