[英]Capturing multiple line output into a Bash variable
我有一個腳本“myscript”,它輸出以下內容:
abc
def
ghi
在另一個腳本中,我調用:
declare RESULT=$(./myscript)
並且$RESULT
獲取值
abc def ghi
有沒有辦法用換行符或'\n'字符存儲結果,這樣我就可以用' echo -e
' output 它?
實際上,RESULT 包含您想要的內容 - 以演示:
echo "$RESULT"
你所展示的就是你從中得到的:
echo $RESULT
如評論中所述,不同之處在於(1)變量的雙引號版本( echo "$RESULT"
)保留了值的內部間距,與變量中表示的值完全相同 - 換行符、制表符、多個空格和all — 而 (2) 不帶引號的版本 ( echo $RESULT
) 用一個空格替換一個或多個空格、制表符和換行符的每個序列。 因此(1)保留輸入變量的形狀,而(2)創建一個可能非常長的 output 單行,其中“單詞”由單個空格分隔(其中“單詞”是非空白字符的序列;不需要'不是任何單詞中的任何字母數字)。
另一個缺陷是命令替換—— $()
——去掉了尾隨的換行符。 可能並不總是很重要,但如果你真的想保留 output 的確切內容,你將不得不使用另一行和一些引用:
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]}"
除了@l0b0 給出的答案之外,我還遇到了一種情況,即我需要通過腳本保留任何尾隨換行符 output並檢查腳本的返回碼。 l0b0 的答案的問題是“echo x”正在重置 $? 回到零......所以我設法想出了這個非常狡猾的解決方案:
RESULTX="$(./myscript; echo x$?)"
RETURNCODE=${RESULTX##*x}
RESULT="${RESULTX%x*}"
所以你的myscript
output 3 行,可能看起來像:
myscript() { echo $'abc\ndef\nghi'; }
或者
myscript() { local i; for i in abc def ghi ;do echo $i; done ;}
好的,這是 function,不是腳本(不需要路徑./
),但 output 是一樣的
myscript
abc
def
ghi
要檢查結果代碼,測試 function 將變為:
myscript() { local i;for i in abc def ghi ;do echo $i;done;return $((RANDOM%128));}
你的操作是正確的:
RESULT=$(myscript)
關於結果代碼,您可以添加:
RCODE=$?
即使在同一行:
RESULT=$(myscript) RCODE=$?
然后
echo $RESULT
abc def ghi
echo "$RESULT"
abc
def
ghi
echo ${RESULT@Q}
$'abc\ndef\nghi'
printf "%q\n" "$RESULT"
$'abc\ndef\nghi'
但為了顯示變量定義,請使用declare -p
:
declare -p RESULT
declare -- RESULT="abc
def
ghi"
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"
read
解析多個output{ 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"
在這里嘗試了大多數解決方案之后,我發現最簡單的事情是顯而易見的 - 使用臨時文件。 我不確定您想對多行 output 做什么,但您可以使用 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。 可能不需要在這里解釋,但有人在評論中抱怨。
怎么樣,它會將每一行讀取到一個變量中,然后可以使用它! 說 myscript output 被重定向到一個名為 myscript_output 的文件
awk '{while ( (getline var < "myscript_output") >0){print var;} close ("myscript_output");}'
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.