捕获多行输出到Bash变量

Par*_*ker 542 variables bash

我有一个脚本'myscript',输出如下:

abc
def
ghi
Run Code Online (Sandbox Code Playgroud)

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

declare RESULT=$(./myscript)
Run Code Online (Sandbox Code Playgroud)

$RESULT获得价值

abc def ghi
Run Code Online (Sandbox Code Playgroud)

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

Jon*_*ler 1017

实际上,RESULT包含你想要的 - 展示:

echo "$RESULT"
Run Code Online (Sandbox Code Playgroud)

你展示的是你得到的:

echo $RESULT
Run Code Online (Sandbox Code Playgroud)

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

  • @troelskn:不同之处在于:(1)变量的双引号版本保留了值的内部间距,与变量,换行符,制表符,多个空格和全部表示的完全相同,而(2)未加引号的版本替换具有单个空格的一个或多个空格,制表符和换行符的每个序列.因此(1)保留输入变量的形状,而(2)创建一个可能非常长的单行输出,其中'单词'由单个空格分隔(其中'单词'是非空白字符序列;有必要任何一个词都不是任何字母数字). (65认同)
  • 为了使答案更容易理解:答案告诉echo"$ RESULT"保留换行符,而echo $ RESULT则不行. (22认同)
  • @CommaToast:你要详细说明吗?跟踪换行丢失; 没有一个简单的方法.领先的空白 - 我不知道他们失去的任何情况. (3认同)
  • 另请参阅[何时在 shell 变量周围加上引号?](http://stackoverflow.com/questions/10067266/when-to-wrap-quotes-around-a-shell-variable) (2认同)

l0b*_*0b0 86

与此另一个缺陷是,命令替换 - $()-带拖尾换行符.可能并不总是重要,但如果你真的想要保留输出的确切内容,你将不得不使用另一行和一些引用:

RESULTX="$(./myscript; echo x)"
RESULT="${RESULTX%x}"
Run Code Online (Sandbox Code Playgroud)

如果要处理所有可能的文件名(以避免在错误的文件上操作等未定义的行为),这一点尤为重要.

  • 我不得不工作一段时间没有从[命令替换]中移除最后一个换行符的破壳(http://www.gnu.org/software/bash/manual/bash.html#Command-Substitution)(它是_not_ [过程替换](http://www.gnu.org/software/bash/manual/bash.html#Process-Substitution)),它几乎破坏了一切.例如,如果你做了``pwd =`pwd`; ls $ pwd/$ file``,你在`/`之前有一个换行符,用双引号括起名字没有帮助.它被迅速修复了.这是在1983年至2005年ICL Perq PNX的时间框架内; shell没有`$ PWD`作为内置变量. (4认同)

小智 17

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

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

  • 您将使用 `readarray` 和进程替换而不是命令替换:`readarray -t RESULT < (./myscript>`。 (4认同)
  • 如果行中有空格,则会计算字段(空格之间的内容)而不是行. (3认同)

小智 15

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

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


F. *_*uri 7

解析多个输出

介绍

所以你的myscript输出 3 行可能看起来像:

myscript() { echo $'abc\ndef\nghi'; }
Run Code Online (Sandbox Code Playgroud)

或者

myscript() { local i; for i in abc def ghi ;do echo $i; done ;}
Run Code Online (Sandbox Code Playgroud)

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

myscript
abc
def
ghi
Run Code Online (Sandbox Code Playgroud)

考虑结果代码

要检查结果代码,测试函数将变为:

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

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

您的操作是正确的:

RESULT=$(myscript)
Run Code Online (Sandbox Code Playgroud)

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

RCODE=$?
Run Code Online (Sandbox Code Playgroud)

即使在同一行:

RESULT=$(myscript) RCODE=$?
Run Code Online (Sandbox Code Playgroud)

然后

echo $RESULT $RCODE
Run Code Online (Sandbox Code Playgroud)
abc def ghi 66
Run Code Online (Sandbox Code Playgroud)
echo "$RESULT"
Run Code Online (Sandbox Code Playgroud)
abc
def
ghi
Run Code Online (Sandbox Code Playgroud)
echo ${RESULT@Q}
Run Code Online (Sandbox Code Playgroud)
$'abc\ndef\nghi'
Run Code Online (Sandbox Code Playgroud)
printf '%q\n' "$RESULT"
Run Code Online (Sandbox Code Playgroud)
$'abc\ndef\nghi'
Run Code Online (Sandbox Code Playgroud)

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

declare -p RESULT RCODE
Run Code Online (Sandbox Code Playgroud)
declare -- RESULT="abc
def
ghi"
declare -- RCODE="66"
Run Code Online (Sandbox Code Playgroud)

2. 解析数组中的多个输出,使用mapfile

将答案存储到myvar变量中:

mapfile -t myvar < <(myscript)
echo ${myvar[2]}
Run Code Online (Sandbox Code Playgroud)
ghi
Run Code Online (Sandbox Code Playgroud)

显示$myvar

declare -p myvar
Run Code Online (Sandbox Code Playgroud)
declare -a myvar=([0]="abc" [1]="def" [2]="ghi")
Run Code Online (Sandbox Code Playgroud)

考虑结果代码

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

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

declare -p myvar RCODE
Run Code Online (Sandbox Code Playgroud)
declare -a myvar=([0]="abc" [1]="def" [2]="ghi")
declare -- RCODE="40"
Run Code Online (Sandbox Code Playgroud)

read3. 通过命令组中的连续解析多个输出

{ read firstline; read secondline; read thirdline;} < <(myscript)
echo $secondline
def
Run Code Online (Sandbox Code Playgroud)

显示变量:

declare -p firstline secondline thirdline
Run Code Online (Sandbox Code Playgroud)
declare -- firstline="abc"
declare -- secondline="def"
declare -- thirdline="ghi"
Run Code Online (Sandbox Code Playgroud)

我经常使用:

{ read foo;read foo total use free foo ;} < <(df -k /)
Run Code Online (Sandbox Code Playgroud)

然后

declare -p use free total
Run Code Online (Sandbox Code Playgroud)
declare -- use="843476"
declare -- free="582128"
declare -- total="1515376"
Run Code Online (Sandbox Code Playgroud)

考虑结果代码

相同的前置步骤:

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

declare -p firstline secondline thirdline RCODE
Run Code Online (Sandbox Code Playgroud)
declare -- firstline="abc"
declare -- secondline="def"
declare -- thirdline="ghi"
declare -- RCODE="50"
Run Code Online (Sandbox Code Playgroud)