在bash中将3个输出行读入3个变量

时间:2015-10-09 22:23:50

标签: linux bash

我有一个生成3行输出的命令,例如

$ ./mycommand
1
asdf
qwer zxcv

我想将这3行分配给3个不同的变量($ a,$ b,$ c),以便

$ echo $a
1
$ echo $b
asdf
$ echo $c
qwer zxcv

我熟悉while循环方法,它通常用于从包含3行组的输出一次读取3行。但考虑到我的命令只输出3行,这似乎不太优雅。

我尝试使用IFS=的各种值组合和read -r a b c的选项,将命令输出作为stdin发送,但我只能得到它将第一行设置为第一个变量。一些例子:

IFS= read -r a b c < <(./mycommand)
IFS=$'\n' read -r a b c < <(./mycommand)
IFS= read -r -d $'\n' < <(./mycommand)

如果我修改我的命令以便3行用空格而不是换行符分隔,只要每个前一行被正确引用,我就可以成功地使用这个变体:

read -r a b c < <(./mycommand)

虽然这对我目前的项目来说是有效的,但它仍然让我烦恼,因为我不能让它以另一种方式运作。因此,我想知道是否有人能够通过3行输出看到并解释我在原始尝试中缺少的内容。

3 个答案:

答案 0 :(得分:6)

如果您想从三行读取数据,请使用三个读数:

{ read -r a; read -r b; read -r c; } < <(./mycommand)

read读取一大块数据然后将其拆分。你无法让它发挥作用,因为你的块总是单行。

答案 1 :(得分:3)

较新的BASH版本支持mapfile命令。使用它,您可以将所有行读入数组:

mapfile -t ary < <(./command)

检查阵列内容:

declare -p ary
declare -a ary='([0]="1" [1]="asdf" [2]="qwer zxcv")'

答案 2 :(得分:3)

也许这个解释对你有用。

  

......它仍然困扰着我,我无法让它以另一种方式运作。因此,我想知道是否有人能够通过3行输出看到并解释我在原始尝试中缺少的内容。

简单:read仅适用于一行(默认情况下)。这样:

#!/bin/bash

mycommand(){ echo -e "1\nasdf\nqwer zxcv"; }

read a b c < <(mycommand)

printf 'first  : %s\nsecond : %s\nthird  : %s\n' "$a" "$b" "$c"

将打印:

first  : 1
second : 
third  : 

但是,使用 null 字符将捕获整个字符串(替换上面的这一行):

    read -d '' a b c < <(mycommand)

将打印:

first  : 1
second : asdf
third  : qwer zxcv

read命令吸收了命令的整个输出,并被分成了具有默认值IFS的部分: Space Tab Enter < / KBD>

在这个具体的例子中,它正常工作,因为最后一个值是一个多于一个&#34;部分&#34;。
但这种处理非常脆弱。例如:该命令的其他可能输出,对变量的赋值将中断:

mycommand(){ echo -e "1 and 2\nasdf and dfgh\nqwer zxcv"; }

输出(错误):

first  : 1
second : and
third  : 2
asdf and dfgh
qwer zxcv

处理很脆弱。为了使其健壮,我们需要使用循环。但是你说这是你已经知道的事情:

#!/bin/bash
mycommand(){ echo -e "1 and 2\nasdf and dfgh\nqwer zxcv"; }

i=0; while read arr[i]; do ((i++)); done < <(mycommand)

printf 'first  : %s\nsecond : %s\nthird  : %s\n' "${arr[0]}" "${arr[1]}" "${arr[2]}"

将(正确)打印:

first  : 1 and 2
second : asdf and dfgh
third  : qwer zxcv

但是,使用bash命令readarray可以使循环更简单:

#!/bin/bash

mycommand(){ echo -e "1 and 2\nasdf and dfgh\nqwer zxcv"; }

readarray -t arr < <(mycommand)

printf 'first  : %s\nsecond : %s\nthird  : %s\n' "${arr[0]}" "${arr[1]}" "${arr[2]}"

使用printf&#34;循环&#34;将使结构适用于任何输入行数:

#!/bin/bash
mycommand(){ echo -e "1 and 2\nasdf and dfgh\n*\nqwer zxcv"; }

readarray -t arr < <(mycommand)
printf 'value : %s\n' "${arr[@]}"

希望这有所帮助。

修改

关于nulls(简单阅读):

在bash中,使用null几乎不可行。具体而言,在大多数条件下,空值会被默默地删除。这种解决方案确实受到这种限制。

在输入中包含null:

mycommand(){ echo -e "1 and 2\nasdf and dfgh\n\000\n*\nqwer zxcv"; }

将使一个简单的read -r -d ''获得第一个null的输入(理解为带有八进制000的字符的null)。

echo "test one:"; echo
echo "input"; echo
mycommand | od -tcx1

echo "output"; echo
read -r -d '' arr < <(mycommand)
echo "$arr" | od -tcx1

将此作为输出:

test one:

input

0000000   1       a   n   d       2  \n   a   s   d   f       a   n   d
         31  20  61  6e  64  20  32  0a  61  73  64  66  20  61  6e  64
0000020       d   f   g   h  \n  \0  \n   *  \n   q   w   e   r       z
         20  64  66  67  68  0a  00  0a  2a  0a  71  77  65  72  20  7a
0000040   x   c   v  \n
         78  63  76  0a
0000044

output

0000000   1       a   n   d       2  \n   a   s   d   f       a   n   d
         31  20  61  6e  64  20  32  0a  61  73  64  66  20  61  6e  64
0000020       d   f   g   h  \n
         20  64  66  67  68  0a
0000026

很明显,读取的值在第一个八进制000处停止 坦率地说,这是可以预期的。

关于nulls(在readarray中):

然而,我必须报告,readarray 停在八进制000但只是默默地删除它(通常的shell特性)。
运行此代码:

#!/bin/bash
mycommand(){ echo -e "1 and 2\nasdf and dfgh\n\000\n*\nqwer zxcv"; }
echo "test two:"; echo
echo "input"; echo
mycommand | od -tcx1

echo "output"; echo
readarray -t arr < <(mycommand)
printf 'value : %s\n' "${arr[@]}"
echo
printf 'value : %s\n' "${arr[@]}"|od -tcx1

呈现此输出:

test two:

input

0000000   1       a   n   d       2  \n   a   s   d   f       a   n   d
         31  20  61  6e  64  20  32  0a  61  73  64  66  20  61  6e  64
0000020       d   f   g   h  \n  \0  \n   *  \n   q   w   e   r       z
         20  64  66  67  68  0a  00  0a  2a  0a  71  77  65  72  20  7a
0000040   x   c   v  \n
         78  63  76  0a
0000044

output

value : 1 and 2
value : asdf and dfgh
value : 
value : *
value : qwer zxcv

0000000   v   a   l   u   e       :       1       a   n   d       2  \n
         76  61  6c  75  65  20  3a  20  31  20  61  6e  64  20  32  0a
0000020   v   a   l   u   e       :       a   s   d   f       a   n   d
         76  61  6c  75  65  20  3a  20  61  73  64  66  20  61  6e  64
0000040       d   f   g   h  \n   v   a   l   u   e       :      \n   v
         20  64  66  67  68  0a  76  61  6c  75  65  20  3a  20  0a  76
0000060   a   l   u   e       :       *  \n   v   a   l   u   e       :
         61  6c  75  65  20  3a  20  2a  0a  76  61  6c  75  65  20  3a
0000100       q   w   e   r       z   x   c   v  \n
         20  71  77  65  72  20  7a  78  63  76  0a
0000113

也就是说,空的000或只是\ 0被静默删除。