web-dev-qa-db-ja.com

複数行の出力をBash変数に取り込む

次のように出力されるスクリプト 'myscript'があります。

abc
def
ghi

別のスクリプトでは、私は呼び出します:

declare RESULT=$(./myscript)

そして$RESULTは値を取得します

abc def ghi

改行または '\ n'文字を使って結果を保存する方法はありますか。そうすれば 'echo -e'を付けて出力できますか?

509
Parker

実際には、RESULTにはあなたが望むものが含まれています。

echo "$RESULT"

あなたが見せるものはあなたが何から得たものです:

echo $RESULT

コメントで述べたように、違いは、(1)変数の二重引用符で囲まれたバージョン(echo "$RESULT")は、変数で表されているとおりに値の内部スペースを保持するということです。 2)引用符で囲まれていないバージョン(echo $RESULT)は、1つ以上の空白、タブ、および改行の各シーケンスを単一のスペースに置き換えます。したがって、(1)は入力変数の形状を保持しますが、(2)は単一のスペースで区切られた「単語」を含む非常に長い1行の出力を作成します(ここで「単語」は空白ではない文字のシーケンスです。どの単語にも英数字を含めることはできません)。

955

これに関するもう1つの落とし穴は、 コマンド置換 - $() - 末尾の改行を削除することです。おそらく常に重要というわけではありませんが、正確にの出力を保存したい場合は、別の行と引用符を使用する必要があります。

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

あなたが all可能なファイル名 を扱いたい場合(これは未定義の振る舞いを避けるために特に重要です)間違ったファイルを操作します。

84
l0b0

特定の行に興味があるなら、result-arrayを使ってください。

declare RESULT=($(./myscript))  # (..) = array
echo "First line: ${RESULT[0]}"
echo "Second line: ${RESULT[1]}"
echo "N-th line: ${RESULT[N]}"
17
user2574210

@ l0b0によって与えられた答えに加えて、私は両方の末尾の改行をスクリプトによって出力し続けるそしてスクリプトのリターンをチェックする必要があるという状況がありましたコード。そしてl0b0の答えの問題は 'echo x'が$をリセットしていたということですか?ゼロに戻る...だから私はこの非常に狡猾な解決策を思いつくことができた:

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

これはどうでしょうか。各行を変数に読み込み、それを後で使用することができます。 myscriptの出力がmyscript_outputというファイルにリダイレクトされると言う

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

ここでほとんどのソリューションを試した後、私が見つけた最も簡単なことは明らかでした-一時ファイルを使用します。複数行の出力で何をしたいのかわかりませんが、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を簡単に押しつぶすことができるので、1行を実行し、stdinをクリアして終了するスクリプトを与えることに注意してください。 sshがそれをするように私は思う?私は最近それを見ました、他のコード例はここにあります: https://unix.stackexchange.com/questions/24260/reading-lines-from-a-file-with-bash-for-vs-while =

もう1回!今回は異なるファイルハンドルを使用しています(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を使用します。おそらくここで説明する必要はありませんが、誰かがコメントで不満を述べました。

0
user1279741