[英]Capturing multiple line output into a Bash variable
I've got a script 'myscript' that outputs the following:我有一个脚本“myscript”,它输出以下内容:
abc
def
ghi
in another script, I call:在另一个脚本中,我调用:
declare RESULT=$(./myscript)
and $RESULT
gets the value并且
$RESULT
获取值
abc def ghi
Is there a way to store the result either with the newlines, or with '\n' character so I can output it with ' echo -e
'?有没有办法用换行符或'\n'字符存储结果,这样我就可以用'
echo -e
' output 它?
Actually, RESULT contains what you want — to demonstrate:实际上,RESULT 包含您想要的内容 - 以演示:
echo "$RESULT"
What you show is what you get from:你所展示的就是你从中得到的:
echo $RESULT
As noted in the comments, the difference is that (1) the double-quoted version of the variable ( echo "$RESULT"
) preserves internal spacing of the value exactly as it is represented in the variable — newlines, tabs, multiple blanks and all — whereas (2) the unquoted version ( echo $RESULT
) replaces each sequence of one or more blanks, tabs and newlines with a single space.如评论中所述,不同之处在于(1)变量的双引号版本(
echo "$RESULT"
)保留了值的内部间距,与变量中表示的值完全相同 - 换行符、制表符、多个空格和all — 而 (2) 不带引号的版本 ( echo $RESULT
) 用一个空格替换一个或多个空格、制表符和换行符的每个序列。 Thus (1) preserves the shape of the input variable, whereas (2) creates a potentially very long single line of output with 'words' separated by single spaces (where a 'word' is a sequence of non-whitespace characters; there needn't be any alphanumerics in any of the words).因此(1)保留输入变量的形状,而(2)创建一个可能非常长的 output 单行,其中“单词”由单个空格分隔(其中“单词”是非空白字符的序列;不需要'不是任何单词中的任何字母数字)。
Another pitfall with this is that command substitution — $()
— strips trailing newlines.另一个缺陷是命令替换——
$()
——去掉了尾随的换行符。 Probably not always important, but if you really want to preserve exactly what was output, you'll have to use another line and some quoting:可能并不总是很重要,但如果你真的想保留 output 的确切内容,你将不得不使用另一行和一些引用:
RESULTX="$(./myscript; echo x)"
RESULT="${RESULTX%x}"
This is especially important if you want tohandle all possible filenames (to avoid undefined behavior like operating on the wrong file).如果您想处理所有可能的文件名(以避免未定义的行为,例如操作错误的文件),这一点尤其重要。
In case that you're interested in specific lines, use a result-array:如果您对特定行感兴趣,请使用结果数组:
declare RESULT=($(./myscript)) # (..) = array
echo "First line: ${RESULT[0]}"
echo "Second line: ${RESULT[1]}"
echo "N-th line: ${RESULT[N]}"
In addition to the answer given by @l0b0 I just had the situation where I needed to both keep any trailing newlines output by the script and check the script's return code.除了@l0b0 给出的答案之外,我还遇到了一种情况,即我需要通过脚本保留任何尾随换行符 output并检查脚本的返回码。 And the problem with l0b0's answer is that the 'echo x' was resetting $?
l0b0 的答案的问题是“echo x”正在重置 $? back to zero... so I managed to come up with this very cunning solution:
回到零......所以我设法想出了这个非常狡猾的解决方案:
RESULTX="$(./myscript; echo x$?)"
RETURNCODE=${RESULTX##*x}
RESULT="${RESULTX%x*}"
So your myscript
output 3 lines, could look like:所以你的
myscript
output 3 行,可能看起来像:
myscript() { echo $'abc\ndef\nghi'; }
or或者
myscript() { local i; for i in abc def ghi ;do echo $i; done ;}
Ok this is a function, not a script (no need of path ./
), but output is same好的,这是 function,不是脚本(不需要路径
./
),但 output 是一样的
myscript
abc
def
ghi
To check for result code, test function will become:要检查结果代码,测试 function 将变为:
myscript() { local i;for i in abc def ghi ;do echo $i;done;return $((RANDOM%128));}
Your operation is correct:你的操作是正确的:
RESULT=$(myscript)
About result code , you could add:关于结果代码,您可以添加:
RCODE=$?
even in same line:即使在同一行:
RESULT=$(myscript) RCODE=$?
Then然后
echo $RESULT
abc def ghi
echo "$RESULT"
abc
def
ghi
echo ${RESULT@Q}
$'abc\ndef\nghi'
printf "%q\n" "$RESULT"
$'abc\ndef\nghi'
but for showing variable definition, use declare -p
:但为了显示变量定义,请使用
declare -p
:
declare -p RESULT
declare -- RESULT="abc
def
ghi"
mapfile
mapfile
Storing answer into myvar
variable:将答案存储到
myvar
变量中:
mapfile -t myvar < <(myscript)
echo ${myvar[2]}
ghi
Showing $myvar
:显示
$myvar
:
declare -p myvar
declare -a myvar=([0]="abc" [1]="def" [2]="ghi")
In case you have to check for result code, you could:如果您必须检查结果代码,您可以:
RESULT=$(myscript) RCODE=$?
mapfile -t myvar <<<"$RESULT"
read
in command group read
解析多个output{ read firstline; read secondline; read thirdline;} < <(myscript)
echo $secondline
def
Showing variables:显示变量:
declare -p firstline secondline thirdline
declare -- firstline="abc"
declare -- secondline="def"
declare -- thirdline="ghi"
I often use:我经常使用:
{ read foo;read foo total use free foo ;} < <(df -k /)
Then然后
declare -p use free total
declare -- use="843476"
declare -- free="582128"
declare -- total="1515376"
Same prepended step:相同的前置步骤:
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"
After trying most of the solutions here, the easiest thing I found was the obvious - using a temp file.在这里尝试了大多数解决方案之后,我发现最简单的事情是显而易见的 - 使用临时文件。 I'm not sure what you want to do with your multiple line output, but you can then deal with it line by line using read.
我不确定您想对多行 output 做什么,但您可以使用 read 逐行处理它。 About the only thing you can't really do is easily stick it all in the same variable, but for most practical purposes this is way easier to deal with.
关于你唯一不能真正做的事情就是轻松地将它们全部放在同一个变量中,但对于大多数实际目的来说,这更容易处理。
./myscript.sh > /tmp/foo
while read line ; do
echo 'whatever you want to do with $line'
done < /tmp/foo
Quick hack to make it do the requested action:快速破解以使其执行请求的操作:
result=""
./myscript.sh > /tmp/foo
while read line ; do
result="$result$line\n"
done < /tmp/foo
echo -e $result
Note this adds an extra line.请注意,这会增加一行。 If you work on it you can code around it, I'm just too lazy.
如果你在它上面工作,你可以围绕它编写代码,我只是太懒了。
EDIT: While this case works perfectly well, people reading this should be aware that you can easily squash your stdin inside the while loop, thus giving you a script that will run one line, clear stdin, and exit.编辑:虽然这个案例运行良好,但阅读本文的人应该知道,您可以轻松地在 while 循环中压缩您的标准输入,从而为您提供一个运行一行、清除标准输入并退出的脚本。 Like ssh will do that I think?
我想像 ssh 会那样做吗? I just saw it recently, other code examples here: https://unix.stackexchange.com/questions/24260/reading-lines-from-a-file-with-bash-for-vs-while
我最近才看到它,这里的其他代码示例: https://unix.stackexchange.com/questions/24260/reading-lines-from-a-file-with-bash-for-vs-while
One more time, This time with a different filehandle (stdin, stdout, stderr are 0-2. so we can use &3 or higher in bash).再一次,这次使用不同的文件句柄(stdin、stdout、stderr 是 0-2。所以我们可以在 bash 中使用 &3 或更高)。
result=""
./test>/tmp/foo
while read line <&3; do
result="$result$line\n"
done 3</tmp/foo
echo -e $result
you can also use mktemp, but this is just a quick code example.您也可以使用 mktemp,但这只是一个快速的代码示例。 Usage for mktemp looks like:
mktemp 的用法如下所示:
filenamevar=`mktemp /tmp/tempXXXXXX`
./test > $filenamevar
Then use $filenamevar like you would the actual name of a file.然后像使用文件的实际名称一样使用 $filenamevar。 Probably doesn't need to be explained here but someone complained in the comments.
可能不需要在这里解释,但有人在评论中抱怨。
How about this, it will read each line to a variable and that can be used subsequently !怎么样,它会将每一行读取到一个变量中,然后可以使用它! say myscript output is redirected to a file called myscript_output
说 myscript output 被重定向到一个名为 myscript_output 的文件
awk '{while ( (getline var < "myscript_output") >0){print var;} close ("myscript_output");}'
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.