我有一个名为'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)则创建了一个可能非常长的单行输出,其中“单词”由单个空格分隔(“单词”是一个非空白字符序列,其中任何单词都不必包含字母数字字符)。$()
— 会删除末尾的换行符。可能并不总是重要的,但如果你真的想要完全保留输出的内容,你将需要使用另一行和一些引用。RESULTX="$(./myscript; echo x)"
RESULT="${RESULTX%x}"
如果你对特定的行感兴趣,可以使用结果数组:
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>
。 - chepner除了@l0b0给出的答案外,我曾遇到这样一种情况,需要保留脚本输出的任何尾随换行符并且检查脚本的返回代码。 而l0b0答案中的'echo x'会将$?重置为零,所以我想出了这个非常狡猾的解决方案:
RESULTX="$(./myscript; echo x$?)"
RETURNCODE=${RESULTX##*x}
RESULT="${RESULTX%x*}"
die()
函数,并且我想使用另一个 usage()
函数来提供消息,但换行符一直被压缩,希望这可以让我解决这个问题。 - dragon788所以,你的 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));}
您的操作是正确的:
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"
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"
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"
help read
和 help mapfile
的内容,获取有关换行符、反斜杠和其他特殊字符的选项! - F. Hauri - Give Up GitHub在尝试了这里大部分的解决方案之后,我发现最简单的方法是显而易见的 - 使用临时文件。我不确定你想要如何处理多行输出,但是你可以使用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 循环中,您可以轻松地压缩 stdin,从而使您的脚本运行一行,清除 stdin 并退出。类似 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
while read -ru $testout line;do echo "对$line执行某些操作";done {testout}< <(./test)
而不是创建临时文件! - F. Hauri - Give Up GitHubawk '{while ( (getline var < "myscript_output") >0){print var;} close ("myscript_output");}'
$IFS
的信息,请参见 What is the exact meaning ofIFS=$'\n'
。 - Peyman Mohamadpour