读取-a数组-d'\ n'<foo,退出代码1


8

如果我尝试执行

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

Answers:


14

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

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

-d选项执行此操作:

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

因此,如果没有该选项,read则会读取换行符,使用in $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 保留反斜杠,但不保留前导或尾随空格。


谢谢!我以为我曾经尝试过$'\ n'方法,但我猜不是:/很高兴知道-r
RasmusWL 2013年

2
在我看来,“最后一行没有换行符的罕见情况”似乎并不是建议“从不使用while read” 的迫切理由。否则,很棒的答案。
格伦·杰克曼(Glenn jackman)2013年

@glennjackman:while read只要循环中没有任何内容,就可以使用。否则,这是一个等待您咬的虫子-相信我,我被咬了。
rici

2
最后一行始终有换行符。这就是定义行的方式:它以换行符结尾。如果非空文件没有以换行符结尾,则它不是文本文件,并且您不能使用诸如shell实用程序之类的文本处理工具read
吉尔斯(Gillles)“所以别再作恶了”

2
@glennjackman:我,我主要使用awk遍历列化文件。对于在文件不太大的地方进行整行迭代,mapfile这很酷。对于快速和肮脏的黑客,我将使用禁止的while循环,但我已停止将其放入生产脚本中。YMMV和我在回答中减弱了警告。
rici

4

这是预期的行为:

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

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

start cmd:> echo -n a b c | { read -a testarray; echo $?; }
1
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.