将多行输出捕获到Bash变量中

时间:2021-10-26 15:41:19

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'输出它?

6 个解决方案

#1


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. 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)变量的双引号版本(echo“$ RESULT”)保留了值的内部间距,与变量中表示的完全相同 - 换行符,制表符,多个空格和all - 而(2)未加引号的版本(echo $ RESULT)用一个空格替换一个或多个空格,制表符和换行符的每个序列。因此(1)保留输入变量的形状,而(2)创建一个可能非常长的单行输出,其中'单词'由单个空格分隔(其中'单词'是非空白字符的序列;有必要任何一个词都不是任何字母数字。

#2


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:

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

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

This is especially important if you want to handle all possible filenames (to avoid undefined behavior like operating on the wrong file).

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

#3


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. And the problem with l0b0's answer is that the 'echo x' was resetting $? back to zero... so I managed to come up with this very cunning solution:

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

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

#4


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]}"

#5


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输出被重定向到一个名为myscript_output的文件

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

#6


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. 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.

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

./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. Like ssh will do that I think? 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

编辑:虽然这种情况非常有效,但阅读本文的人应该知道你可以轻松地在while循环中压缩你的stdin,从而为你提供一个运行一行,清除stdin和退出的脚本。像ssh那样我会这样做吗?我刚看到它,其他代码示例如下: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. Usage for mktemp looks like:

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

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

Then use $filenamevar like you would the actual name of a file. Probably doesn't need to be explained here but someone complained in the comments.

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

#1


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. 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)变量的双引号版本(echo“$ RESULT”)保留了值的内部间距,与变量中表示的完全相同 - 换行符,制表符,多个空格和all - 而(2)未加引号的版本(echo $ RESULT)用一个空格替换一个或多个空格,制表符和换行符的每个序列。因此(1)保留输入变量的形状,而(2)创建一个可能非常长的单行输出,其中'单词'由单个空格分隔(其中'单词'是非空白字符的序列;有必要任何一个词都不是任何字母数字。

#2


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:

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

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

This is especially important if you want to handle all possible filenames (to avoid undefined behavior like operating on the wrong file).

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

#3


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. And the problem with l0b0's answer is that the 'echo x' was resetting $? back to zero... so I managed to come up with this very cunning solution:

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

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

#4


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]}"

#5


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输出被重定向到一个名为myscript_output的文件

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

#6


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. 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.

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

./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. Like ssh will do that I think? 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

编辑:虽然这种情况非常有效,但阅读本文的人应该知道你可以轻松地在while循环中压缩你的stdin,从而为你提供一个运行一行,清除stdin和退出的脚本。像ssh那样我会这样做吗?我刚看到它,其他代码示例如下: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. Usage for mktemp looks like:

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

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

Then use $filenamevar like you would the actual name of a file. Probably doesn't need to be explained here but someone complained in the comments.

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