たかまるの雑記

たまに更新

標準出力と標準エラー出力を別の変数に入れる(2)

つづき

takamaruo.hatenablog.com

プロセス置換のつかえないshで、stdoutとstderrを別々の変数に入れる方法はあるのだろうか。


サンプル コマンド
 command() {
  echo "[-- stdout1 --]"
  echo "[-- stdout2 --]"
  echo "[-- stderr1 --]" >&2
  echo "[-- stderr2 --]" >&2
  return 3
}


1. evalを使う

bashの時と同じようにevalと使う

unset out stdout stderr ret

eval "stderr=\"$({ stdout=$(command);ret=$?;echo "\""; typeset -p stdout; typeset -p ret; } 2>&1);"

echo $ret
echo -e "stdout=$stdout\nstderr=$stderr"
結果
3

stdout=[-- stdout1 --]
[-- stdout2 --]
stderr=[-- stderr1 --]
[-- stderr2 --]

stderrの代入でクォートしないとエラーになってしまうので、=の前に\"を入れた。
ただ、閉じる\"を最後の)の後ろに書くと、typeset (declare)のダブルクォーテーションが2重になってしまう。
なので、途中にechoを入れて"を出力してみた。
結果、エラーにはならないけど、stderrの最後に改行が入ってしまう。


2. 区切り文字を追加する

標準出力と標準エラー出力を同じ変数に入れる。
変数に入れるときに分けるための文字列を追加する。
そして、入れたあとにsedで別々の変数に分ける。

unset out stdout stderr

out=$({ echo "#####$(command)"; } 2>&1)

echo $?

stdout=$(echo "$out" | sed -nre '/#####/,$s/^(#####|)//p')
stderr=$(echo "$out" | sed -nre '/#####/,$!p')

echo -e "stdout=$stdout\nstderr=$stderr"
結果
0

stdout=[-- stdout1 --]
[-- stdout2 --]
stderr=[-- stderr1 --]
[-- stderr2 --]

別々の変数に入れることはできたけど、 設定する文字列も考えないといけないし、あんまりよくない気がする。

戻り値をとるときはこんな感じ。

out=$({ a=$(command);b=$?;echo "#####$a";return $b; } 2>&1)

echo $?
0


最初のevalを使う方法のダブルクォーテーションがなぞ。
これが解決できれば良いのだけれど、ぜんぜんわからない。
この件についてはkshがいいですね。