在bash
劇本我想分配內建一個數組變量times
的輸出,但我發現沒有更好的辦法比擊:分配的「次」內置輸出到一個變量
tempnam=/tmp/aaa_$$_$RANDOM
times > ${tempnam}
mapfile -t times_a < ${tempnam}
我將輸出寫入臨時文件並將其讀回到times_a數組中,因爲pipeline或$(times)
將在子外殼中執行並返回錯誤的值。
沒有臨時文件的任何更好的解決方案?
在bash
劇本我想分配內建一個數組變量times
的輸出,但我發現沒有更好的辦法比擊:分配的「次」內置輸出到一個變量
tempnam=/tmp/aaa_$$_$RANDOM
times > ${tempnam}
mapfile -t times_a < ${tempnam}
我將輸出寫入臨時文件並將其讀回到times_a數組中,因爲pipeline或$(times)
將在子外殼中執行並返回錯誤的值。
沒有臨時文件的任何更好的解決方案?
您需要解決的根本問題是如何在不使用臨時文件的情況下同時執行time
和變量賦值。幾乎每種方法Bash都提供了將一個東西的輸出管道輸出到另一個東西,或者捕獲一個命令的輸出,其中一方在子外殼中工作。
這裏是你可以不用臨時文件的一種方法,但我會提醒你,這不是很漂亮,這是無法移植到其他炮彈,它至少需要擊4:
coproc co { cat; }; times 1>&${co[1]}; eval "exec ${co[1]}>&-"; mapfile -tu ${co[0]} times_a
我會爲你解決這個問題:
coproc co { cat; }
這創建了一個協處理器;這是一個在後臺運行的進程,但您可以通過管道與標準輸入和標準輸出進行通信,這些FD是${co[0]}
(標準爲cat
)和${co[1]}
(標準爲cat
)。這些命令在一個子shell中執行,所以我們不能在那裏執行任何一個目標(運行times
或讀入一個變量),但我們可以使用cat
來簡單地將輸入傳遞給輸出,然後使用該管道在當前shell中與times
和mapfile
交談。
times >&${co[1]};
運行times
,其重定向標準輸出到標準的cat
命令。
eval "exec ${co[1]}>&-"
關閉cat
命令的輸入結束。如果我們不這樣做,cat
將繼續等待輸入,保持其輸出打開,並且mapfile
將繼續等待輸入,導致您的shell掛起。 exec
,當不傳遞任何命令時,只需將其重定向應用到當前shell;重定向到-
關閉FD。我們需要使用eval
,因爲Bash似乎遇到了exec ${co[1]}>&-
的問題,將FD解釋爲命令而不是重定向的一部分;使用eval
允許首先替換該變量,然後執行。
mapfile -tu ${co[0]} times_a
最後我們實際上從協處理器中讀取標準數據。我們設法在這個shell中運行了times
和mapfile
命令,並且沒有使用臨時文件,儘管我們在兩個命令之間使用了臨時進程作爲管道。
請注意,這有一個微妙的比賽。如果你逐個執行這些命令,而不是全部作爲一個命令,則最後一個命令失敗;因爲當你關閉cat
的標準時,它退出,導致協處理器退出並且FD關閉。看起來,當全部在一行上執行時,mapfile
被執行得足夠快,以至於協處理在運行時仍然打開,因此它可以從管道讀取;但我可能會很幸運。我還沒有想出解決這個問題的好方法。
總而言之,只需寫出臨時文件就簡單多了。我會用mktemp
生成一個文件名,如果你在一個腳本的時候,添加陷阱,以保證在退出之前,你清理臨時文件:
tempnam=$(mktemp)
trap "rm '$tempnam'" EXIT
times > ${tempnam}
mapfile -t times_a < ${tempnam}
一種可能性做同樣的事情會
times > >(other_command)
這是一個過程替代combided輸出重定向。這種方式times
在當前shell中執行,輸出重定向到一個新的子進程。因此,使用mapfile
做這件事並沒有多大意義,因爲該命令不會在同一個shell中執行,而且這可能不是您想要的。這種情況有點棘手,因爲你不能調用在子shell中執行的shell內置函數。
哇,好問題。
一個改進就是使用mktemp,這樣你就不會依賴隨機性來保持文件的獨特性。
TMPFILE=$(mktemp aaa_XXXXXXXXXX)
times > "$TMPFILE"
mapfile -t times_a < ${tempnam}
rm "$TMPFILE"
此外,我使用替代mapfile(因爲我沒有mapfile)。
a=0; for var in $(cat "$TMPFILE"); do ((a++)); TIMES_A[$a]=$var; done
但是,是啊,我不明白你怎麼能沒有文件或命名管道。
我希望我能更給予好評這一點,我已經學會了很多讀這個,真的很好的答案! – higuaro