read -a array -d '\n' < foo, 退出代码 1

read -a array -d '\n' < foo, 退出代码 1

如果我尝试执行

read -a fooArr -d '\n' < bar

退出代码是 1——即使它完成了我想要的;将 的每一行放入bar数组的一个元素中fooArr(使用 bash 4.2.37)。

有人可以解释为什么会发生这种情况


我找到了其他方法来解决这个问题,如下所示,所以这不是我所要求的。

for ((i=1;; i++)); do
    read "fooArr$i" || break;
done < bar

或者

mapfile -t fooArr < bar

答案1

需要解释的是该命令似乎有效,而不是其退出代码

'\n'是两个字符:一个反斜杠\和一个字母n。你认为你需要的是$'\n',它是一个换行符(但这也不正确,见下文)。

-d选项执行以下操作:

  -d delim  continue until the first character of DELIM is read, rather
            than newline

因此,如果没有该选项,read将读取到换行符,使用中的字符作为$IFS分隔符将该行拆分为单词,然后将单词放入数组中。如果您指定-d $'\n',将行分隔符设置为换行符,则可以完全相同的事情。设置-d '\n'意味着它将读取到第一个反斜杠(但是,再次参见下文),这是 中的第一个字符delim。由于文件中没有反斜杠,因此read将在文件末尾终止,并且:

Exit Status:
The return code is zero, unless end-of-file is encountered, read times out,
or an invalid file descriptor is supplied as the argument to -u.

这就是退出代码为 1 的原因。

从您相信该命令有效的事实来看,我们可以得出结论,文件中没有空格,因此read,在徒劳地希望找到反斜杠的情况下读取整个文件后,将用空格分隔它(默认值$IFS),包括换行符。因此,每一行(或每个单词,如果一行包含多个单词)都会被存储到数组中。

反斜杠被盗的神秘案例

现在,我怎么知道该文件不包含任何反斜杠?因为您没有将-r标志提供给read

  -r                do not allow backslashes to escape any characters

因此,如果文件中有任何反斜杠,它们就会被删除,除非其中两个连续。当然,有证据表明read退出代码为 1,这表明它没有找到反斜杠,因此也没有两个连续出现。

要点

如果几乎每个命令后面都没有隐藏陷阱,那么 Bash 就不会是 bash,也不read例外。这里有几个:

  1. 除非您指定-r,否则read将解释反斜杠转义序列。除非这实际上是您想要的(偶尔是,但只是偶尔),否则您应该记住指定-r以避免在输入中存在反斜杠的罕见情况下字符消失。

  2. 返回read退出代码 1 并不意味着它失败。除了找到行终止符之外,它很可能已经成功。因此,要小心这样的循环:因为在极少数情况下,最后一行末尾没有换行符,while read -r LINE; do something with LINE; done 它将无法处理最后一行。do something

  3. read -r LINE保留反斜杠,但不保留前导或尾随空格。

答案2

这是预期的行为:

返回代码为零,除非遇到文件结尾,[...]

start cmd:> echo a b c | { read -a testarray; echo $?; }
0

start cmd:> echo -n a b c | { read -a testarray; echo $?; }
1

相关内容