サブシェルを使用せずにbash機能から出力をキャプチャする

サブシェルを使用せずにbash機能から出力をキャプチャする

パイプからコマンドを受け取るbashスクリプトがあります。コマンドを見て実行します。しかし、後で呼び出すことができるbash関数の「サイドローディング」をサポートしたいと思います。

以下は、スクリプトが実行する必要があるタスクのアイデアを提供するいくつかの入出力の例です。

# left of the arrow is input, right of arrow is output
"echo 'test'" -> "test"
"_a() { echo 'test' }" -> ""
"_a" -> "test"

通常のコマンドでは正常に機能しますが、機能のロードに問題があります。私はこれがサブシェルでユーザー入力を実行しているので、親は定義された関数を使用して将来のコマンドを実行できないためだと思います。ファイル記述子を使用して(stdoutおよびstderr)にデータを保存しようとしましたが、eval機能しませんでした。現在、次のようなものがあります。

exec 3>&1
eval 'echo "Hello World"' >&3
read -u 3 var
exec 3>&- 
echo "$var"

可能ですか?

ベストアンサー1

これはあなたに役立ちます:

$ cat runcmd
#!/usr/bin/env bash

tmpout=$(mktemp) || exit
tmperr=$(mktemp) || exit
trap 'rm -f -- "$tmpout" "$tmperr"; exit' EXIT

while IFS= read -r -a cmd; do
    printf '==========\n'
    declare -p cmd

    eval "${cmd[@]}" > "$tmpout" 2>"$tmperr"

    readarray -t out < "$tmpout"
    readarray -t err < "$tmperr"

    declare -p out
    declare -p err
done

$ cat <<'EOF' | ./runcmd
echo 'test of echo with globbing * and variables $RANDOM and    spaces'
_a() { echo 'test of a()'; }
_a
awk 'BEGIN{print "multi line\noutput string"; print "and multi\nline error\nmessage" | "cat>&2"}'
EOF
==========
declare -a cmd=([0]="echo 'test of echo with globbing * and variables \$RANDOM and    spaces'")
declare -a out=([0]="test of echo with globbing * and variables \$RANDOM and    spaces")
declare -a err=()
==========
declare -a cmd=([0]="_a() { echo 'test of a()'; }")
declare -a out=()
declare -a err=()
==========
declare -a cmd=([0]="_a")
declare -a out=([0]="test of a()")
declare -a err=()
==========
declare -a cmd=([0]="awk 'BEGIN{print \"multi line\\noutput string\"; print \"and multi\\nline error\\nmessage\" | \"cat>&2\"}'")
declare -a out=([0]="multi line" [1]="output string")
declare -a err=([0]="and multi" [1]="line error" [2]="message")

しかし、入力として提供されたコードを実行するプログラムを書くのは危険ですので、必ず読んでください。Bash FAQ:変数にコマンドを入れようとしていますが、複雑な場合は常に失敗します!そしてBashで評価を避けるべき理由と何を使うべきですか?これを実装する前に。

おすすめ記事