我有一个脚本“myscript”,它输出以下内容:
abc
def
ghi
在另一个脚本中,我调用:
declare RESULT=$(./myscript)
$RESULT
获取值
abc def ghi
有没有办法用换行符或'\n'字符存储结果,以便我可以用'echo -e
'输出它?
实际上,RESULT 包含您想要的内容 - 以演示:
echo "$RESULT"
你所展示的就是你从中得到的:
echo $RESULT
如评论中所述,不同之处在于 (1) 变量 (echo "$RESULT"
) 的双引号版本保留了值的内部间距,与变量中表示的值完全相同——换行符、制表符、多个空格等等——而 (2) 未加引号的版本 (echo $RESULT
) 将一个或多个空格、制表符和换行符的每个序列替换为一个空格。因此 (1) 保留输入变量的形状,而 (2) 创建一个可能非常长的单行输出,其中“单词”由单个空格分隔(其中“单词”是非空白字符序列;不需要'不是任何单词中的任何字母数字)。
另一个陷阱是 command substitution - $()
- 去除尾随换行符。可能并不总是很重要,但如果你真的想准确地保留输出的内容,你将不得不使用另一行和一些引用:
RESULTX="$(./myscript; echo x)"
RESULT="${RESULTX%x}"
如果您想要 handle all possible filenames(以避免未定义的行为,例如操作错误的文件),这一点尤其重要。
pwd=`pwd`; ls $pwd/$file
,则在 /
之前有一个换行符,并且将名称用双引号括起来没有帮助。很快就修好了。这可以追溯到 1983-5 年 ICL Perq PNX 的时间框架; shell 没有 $PWD
作为内置变量。
如果您对特定行感兴趣,请使用结果数组:
declare RESULT=($(./myscript)) # (..) = array
echo "First line: ${RESULT[0]}"
echo "Second line: ${RESULT[1]}"
echo "N-th line: ${RESULT[N]}"
readarray
并处理替换而不是命令替换:readarray -t RESULT < <(./myscript>
。
除了@l0b0 给出的答案之外,我还遇到了一种情况,即我需要保留脚本输出的任何尾随换行符并检查脚本的返回码。 l0b0 的答案的问题是“echo x”正在重置 $?回到零......所以我设法想出了这个非常狡猾的解决方案:
RESULTX="$(./myscript; echo x$?)"
RETURNCODE=${RESULTX##*x}
RESULT="${RESULTX%x*}"
die ()
函数来接受任意退出代码和可选的消息,并且我想使用另一个 usage ()
函数来提供消息,但换行符不断得到被压扁了,希望这能让我解决这个问题。
解析多个输出
介绍
因此,您的 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 $RCODE
abc def ghi 66
echo "$RESULT"
abc
def
ghi
echo ${RESULT@Q}
$'abc\ndef\nghi'
printf "%q\n" "$RESULT"
$'abc\ndef\nghi'
但要显示变量定义,请使用 declare -p
:
declare -p RESULT RCODE
declare -- RESULT="abc
def
ghi"
declare -- RCODE="66"
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"
declare -p myvar RCODE
declare -a myvar=([0]="abc" [1]="def" [2]="ghi")
declare -- RCODE="40"
3.在命令组中通过连续读取来解析多个输出
{ 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"
help read
和 help mapfile
以了解有关 换行符、反斜杠 和其他特性的选项!
在这里尝试了大多数解决方案之后,我发现最简单的事情是显而易见的 - 使用临时文件。我不确定您想对多行输出做什么,但是您可以使用 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
请注意,这会增加一行。如果你在它上面工作,你可以围绕它编写代码,我只是太懒了。
编辑:虽然这个案例运行良好,但阅读本文的人应该知道,您可以轻松地在 while 循环中压缩您的标准输入,从而为您提供一个运行一行、清除标准输入并退出的脚本。我认为像 ssh 会那样做吗?我最近才看到它,这里的其他代码示例:https://unix.stackexchange.com/questions/24260/reading-lines-from-a-file-with-bash-for-vs-while
再一次!这次使用不同的文件句柄(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
您也可以使用 mktemp,但这只是一个快速的代码示例。 mktemp 的用法如下所示:
filenamevar=`mktemp /tmp/tempXXXXXX`
./test > $filenamevar
然后像使用文件的实际名称一样使用 $filenamevar。可能不需要在这里解释,但有人在评论中抱怨。
bash
pitfalls。
read
命令扩展 -u 3
从文件描述符 3 中读取。
while read -ru $testout line;do echo "do something with $line";done {testout}< <(./test)
而不是创建临时文件!
怎么样,它会将每一行读取到一个变量中,然后可以使用它!假设 myscript 输出被重定向到一个名为 myscript_output 的文件
awk '{while ( (getline var < "myscript_output") >0){print var;} close ("myscript_output");}'