捕获多行输出到Bash变量

时间:2009-03-05 04:32:18

标签: bash variables

我有一个脚本'myscript',输出以下内容:

abc
def
ghi

在另一个脚本中,我打电话给:

declare RESULT=$(./myscript)

$RESULT获取值

abc def ghi

有没有办法用换行符或'\ n'字符存储结果,以便我可以用'echo -e'输出?

7 个答案:

答案 0 :(得分:949)

实际上,RESULT包含您想要的内容 - 演示:

echo "$RESULT"

你展示的是你得到的:

echo $RESULT

正如评论中所指出的,区别在于:(1)变量的双引号版本(echo "$RESULT")保留了值的内部间距,与变量中表示的完全相同 - 换行符,制表符,多个空白和所有 - 而(2)未加引号的版本(echo $RESULT)用一个空格替换一个或多个空格,制表符和换行符的每个序列。因此(1)保留输入变量的形状,而(2)创建一个可能非常长的单行输出,其中'单词'由单个空格分隔(其中'单词'是非空白字符序列;有必要在任何一个词中都不是任何字母数字。)

答案 1 :(得分:84)

另一个陷阱是command substitution - $() - 剥离尾随换行符。可能并不总是重要,但如果你真的想保留完全输出的内容,你将不得不使用另一行和一些引用:

RESULTX="$(./myscript; echo x)"
RESULT="${RESULTX%x}"

如果您想要handle all possible filenames(以避免在错误的文件上操作等未定义的行为),这一点尤其重要。

答案 2 :(得分:17)

如果您对特定行感兴趣,请使用结果数组:

declare RESULT=($(./myscript))  # (..) = array
echo "First line: ${RESULT[0]}"
echo "Second line: ${RESULT[1]}"
echo "N-th line: ${RESULT[N]}"

答案 3 :(得分:15)

除了@ l0b0给出的答案之外,我还有这样的情况:我需要通过脚本输出任何尾随换行符,检查脚本的返回码。 而l0b0的答案问题是'echo x'正在重置$?回到零......所以我设法提出了这个非常狡猾的解决方案:

RESULTX="$(./myscript; echo x$?)"
RETURNCODE=${RESULTX##*x}
RESULT="${RESULTX%x*}"

答案 4 :(得分:0)

这个怎么样,它会读取变量的每一行,然后可以使用! 说myscript输出被重定向到一个名为myscript_output

的文件
awk '{while ( (getline var < "myscript_output") >0){print var;} close ("myscript_output");}'

答案 5 :(得分:0)

解析多个输出

简介

因此,您的myscript输出3行,如下所示:

myscript() { echo $'abc\ndef\nghi'; }

myscript() { local i; for i in abc def ghi ;do echo $i; done ;}

好吧,这是一个函数,而不是脚本(不需要路径./),但是输出是相同的

myscript
abc
def
ghi

考虑结果代码

要检查结果代码,测试功能将变为:

myscript() { local i;for i in abc def ghi ;do echo $i;done;return $((RANDOM%128));}

1。将多个输出存储在一个变量中,显示换行符

您的操作正确:

RESULT=$(myscript)

关于结果代码,您可以添加:

RCODE=$?

即使在同一行:

RESULT=$(myscript) RCODE=$?

然后

echo $RESULT 
abc def ghi

echo "$RESULT"
abc
def
ghi

echo ${RESULT@Q}
$'abc\ndef\nghi'

printf "%q\n" "$RESULT"
$'abc\ndef\nghi'

但要显示变量定义,请使用declare -p

declare -p RESULT
declare -- RESULT="abc
def
ghi"

2。使用mapfile

解析数组中的多个输出

将答案存储到myvar变量中:

mapfile -t myvar < <(myscript)
echo ${myvar[2]}
ghi

显示$myvar

declare -p myvar
declare -a myvar=([0]="abc" [1]="def" [2]="ghi")

考虑结果代码

如果必须检查结果代码,可以:

RESULT=$(myscript) RCODE=$?
mapfile -t myvar <<<"$RESULT"

3。通过命令组中的连续read解析多个输出

{ read firstline; read secondline; read thirdline;} < <(myscript)
echo $secondline
def

显示变量:

declare -p firstline secondline thirdline
declare -- firstline="abc"
declare -- secondline="def"
declare -- thirdline="ghi"

我经常使用:

{ read foo;read foo total use free foo ;} < <(df -k /)

然后

declare -p use free total
declare -- use="843476"
declare -- free="582128"
declare -- total="1515376"

考虑结果代码

相同的前置步骤:

RESULT=$(myscript) RCODE=$?
{ read firstline; read secondline; read thirdline;} <<<"$RESULT"

declare -p firstline secondline thirdline RCODE
declare -- firstline="abc"
declare -- secondline="def"
declare -- thirdline="ghi"
declare -- RCODE="50"

答案 6 :(得分:-1)

在尝试了大多数解决方案之后,我发现最简单的事情就是使用临时文件。我不确定你想用你的多行输出做什么,但你可以使用read逐行处理它。关于你唯一不能真正做到的事情就是把它全部放在同一个变量中,但是对于大多数实际用途来说这更容易处理。

./myscript.sh > /tmp/foo
while read line ; do 
    echo 'whatever you want to do with $line'
done < /tmp/foo

快速破解以使其执行请求的操作:

result=""
./myscript.sh > /tmp/foo
while read line ; do
  result="$result$line\n"
done < /tmp/foo
echo -e $result

注意这会增加额外的一行。如果你正在使用它,你可以围绕它进行编码,我太懒了。

编辑:虽然这种情况非常有效,但是阅读此内容的人应该知道你可以轻松地将你的stdin压缩到while循环中,从而为你提供一个运行一行,清除stdin和退出的脚本。像ssh那样我会这样做吗?我刚刚看到它,其他代码示例在这里:https://unix.stackexchange.com/questions/24260/reading-lines-from-a-file-with-bash-for-vs-while

再一次!这次使用不同的文件句柄(stdin,stdout,stderr为0-2,所以我们可以在bash中使用&amp; 3或更高版本。)

result=""
./test>/tmp/foo
while read line  <&3; do
    result="$result$line\n"
done 3</tmp/foo
echo -e $result

你也可以使用mktemp,但这只是一个快速的代码示例。 mktemp的用法如下:

filenamevar=`mktemp /tmp/tempXXXXXX`
./test > $filenamevar

然后使用$ filenamevar,就像使用文件的实际名称一样。可能不需要在这里解释,但有人在评论中抱怨。