如何使用<<<操作符读取整行?

3

我需要验证一些程序输出。我知道这个输出恰好包含三行,我希望将它们存储在不同的变量中以便于访问。我尝试了几种不成功的方式。

IFS=$'\n' read line1 line2 line3 <<< $(grep pattern file.log)
IFS='' read line1 line2 line3 <<< $(grep pattern file.log)

是否可以将read<<<组合起来实现我想要的效果?如何做到?

如果不可能,那么是什么原因呢?你有什么替代方案建议吗?

谢谢。


1
看一下这个问题。它将行放入一个数组中,然后你可以重新分配给line1等变量。 - n0741337
5个回答

5
{
    read line1
    read line2
    read line3
} < <(grep pattern file.log) 

我认为在here文档(<<<)之后使用命令替换符($())是不必要的曲解,同样地,试图欺骗read 一次读取多行也是如此。这种情况下,使用多个read在复合命令中是自然的解决方案。


其他读取的用法让我误以为我可以轻松地一次性读取多行;-) - Philippe A.

2

我发现如何让它运作了。关键在于使用双引号。

首先,我尝试了这个:

data=$(grep pattern file.log)
IFS=$'\n' read -d '' -r line1 line2 line3 <<< "$data"

后来发现如果我保留双引号,这个变量其实并不是必须的:

IFS=$'\n' read -d '' -r line1 line2 line3 <<< "$(grep pattern file.log)"

默认情况下,换行符表示数据结束。为了避免read在第一行后停止工作,我使用-d ''覆盖了默认设置。

默认情况下,字段分隔符是<space><tab><newline>。由于我想读取整行,所以将IFS设置为$'\n'

请注意,-r并不是解决方案的核心。我添加它是为了避免输入中的反斜杠引起问题。

编辑

使用read<<<有一个微妙但重要的缺点:空行将完全消失。

data="1

3"
IFS=$'\n' read -d '' -r line1 line2 line3 <<< "$data"
echo ${line1:-blank}
echo ${line2:-blank}
echo ${line3:-blank}

output:
1
3
blank

如果您尝试使用-a将行存储到数组中,情况也是一样的:

IFS=$'\n' read -d '' -r -a line_ar <<< "$data"
echo ${line_ar[0]:-blank}
echo ${line_ar[1]:-blank}
echo ${line_ar[2]:-blank}

output:
1
3
blank

然而,您仍将使用以下结构获取所有行:
while read -r line ; do
  echo ${line:-blank}
done <<< "$data"

output:

1
blank
3

如果行数非常有限,则最好像kojiro建议的那样使用多个读取。然而,使用<<<是完全合法的:

{ 
  read -r line1
  read -r line2
  read -r line3
} <<< "$data"

echo ${line1:-blank}
echo ${line2:-blank}
echo ${line3:-blank}

记得将"$var"用双引号括起来,以展开换行符。


1
IFS 设置为 \n 并传递 -d ''read。此外,您可以使用进程替换而不是 here 字符串。
while IFS=$'\n' read -d'' -r line1 line2 line3; do :; done < <(grep pattern file.log)

0
使用数组。
read -a array < <(grep pattern file.log)
# Optional
line1=${array[0]}
line2=${array[1]}
line3=${array[2]}

然而,我建议kojiro的答案


0
while read -r arry[x]; do 
    ((x++)); 
done < <(grep pattern file.log)

这将创建一个名为arry的数组,其中3行将属于从0开始的每个索引。


1
似乎在数组末尾创建了一个额外的空元素。 - iruvar
1
看起来你需要学习 mapfile 内置命令:mapfile -t arry < <(grep pattern file.log) 可以更高效地实现这个目的。 - gniourf_gniourf
谢谢分享,@gniourf_gniourf。看起来确实不错,甚至不会在末尾创建一个空元素。除了只适用于bash 4之外,还有其他可能的缺点吗? - jaypal singh
@JS 这样做会更快,但我不确定你能否称之为一个缺点 ;)。但你说得对,它只适用于 Bash 4,而在我看来,每个人都应该使用它 :) - gniourf_gniourf

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接