在 bash 中分割 grep 的输出

在 bash 中分割 grep 的输出

grep我正在尝试使用, 通过管道读取 bash 中的一行文本以tail获取文件的最后一行,然后将该行的前三个“单词”(即使用空格分隔它们)分割为数组的元素。

如果我尝试使用循环遍历输出中的元素for,它会很好地工作,并且我会得到我想要的元素列表:

[] foo=$(grep select file.txt | tail -n 1)
[] echo $foo
0.47331 5.11188 13.1615 # select

[] for x in $foo; do echo $x; done
0.47331
5.11188
13.1615
#
select

这正是我想要它做的!

但是,如果我尝试取出包含 前三个元素的数组foo,我将无法使其工作:

[] echo "${foo[@]:0:2}"
0.47331 5.11188 13.1615 # select 4.95294 13.5177

特别奇怪的是,该行末尾的最后两个值实际上是来自第一的select包含in 的行file.txt(甚至不是该行的前两项,而是第二项和第三项!),所以它们根本不应该是foo...的一部分

同样,如果我尝试简单地从 中切出一个“单词” foo,我会得到一个奇怪的输出:

[] echo "${foo[0]}"
0.47331 5.11188 13.1615 # select

[] echo "${foo[1]}"
4.95294

(同样,最后一个值是一个不应该的值,据我所知,即使是 in foo,它也是第一行的第二项selectin file.txt...)。

我需要了解发生了什么,以及如何得到我想要的输出,即 array 0.47331 5.11188 13.1615

答案1

$foo不是数组;它是一个包含多个空格分隔的单词的字符串。如果您希望它是一个数组,请将其指定为一个:

foo=( $(grep 'select' file.txt | tail -n 1) )

现在您可以引用${foo[0]}或前三个元素作为${foo[@]:0:3}

请注意,它将${foo[@]}包含最后一个匹配行中的所有五个元素,因为这里没有任何内容可以仅提取前三个元素。如果你愿意的话,你可以把它foo=("${foo[@]:0:3}")切成${foo[@]}合适的尺寸。

或者,如果您想创建仅包含前三个元素的数组,可以awk像这样使用:

foo=( $(awk '/select/ { a=$1; b=$2; c=$3 } END { print a,b,c }' file.txt) )

答案2

这可以避免将数据读入变量:

$ grep -F select file | tail -n 1 | cut -d ' ' -f 1-3
0.47331 5.11188 13.1615

要将值放入 中的数组中bash,请使用mapfile(或readarray):

$ mapfile -t arr < <( grep -F select file | tail -n 1 | cut -d ' ' -f 1-3 | tr ' ' '\n' )
$ printf 'arr: %s\n' "${arr[@]}"
arr: 0.47331
arr: 5.11188
arr: 13.1615

我使用tr将数字之间的空格更改为换行符。这样,数组中最后一个值的末尾就不会出现尾随换行符。


您显然可以使用,而不是尴尬的grep+ tail+ cut+管道tr

awk '/select/ { a=$1; b=$2; c=$3 } END { printf("%s\n%s\n%s\n", a, b, c) }'

或者进程替换中类似的东西<(...)

相关内容