サブシェルでコマンドを実行せずにコマンド出力を変数に割り当てるにはどうすればよいですか?

サブシェルでコマンドを実行せずにコマンド出力を変数に割り当てるにはどうすればよいですか?

次の機能がある場合:

TEST()
{
    if [[ "$1" == "hi" ]]
    then
        exit 1
    fi

    echo "Some text"
}

現在のシェルでこの関数を実行すると:

TEST "hi"

すべてが期待どおりに動作します。関数のif文がtrueになり、スクリプト全体が終了します。一方、私がそうするなら:

FUNCTION_OUTPUT=$(TEST "hi")

このようにして、変数の関数からstdoutをキャプチャできます。関数内のifステートメントはまだtrueで、「exit 1」は引き続き実行されますが、サブシェルで実行されているため、スクリプトは引き続き実行されます。

VAR_NAME = $()を使用してサブシェルで何かを実行して変数に割り当てるのではなく、私の関数の "exit 1"行が実際にスクリプト全体を終了するように現在のシェルでこれを実行する方法はありますか?

答え1

変数の割り当てはただ簡単なコマンドだから、あなたは使用することができますif条件関数が成功したか失敗したかを確認してください。

if ! FUNCTION_OUTPUT=$(TEST hi); then
  echo Function return non-zero status
  exit 1
fi

# This line never printed
printf '%s\n' "$FUNCTION_OUTPUT"

関数が成功すると、FUNCTION_OUTPUT関数の結果を含む変数が得られます。

if ! FUNCTION_OUTPUT=$(TEST hii); then
  echo Function return non-zero status
  exit 1
fi

# Output content of FUNCTION_OUTPUT
printf '%s\n' "$FUNCTION_OUTPUT"

答え2

コマンドをファイルにリダイレクトし、組み込みコマンドを使用してファイルを変数として読み込みますmapfile

答え3

スクリプトを終了する方法はいくつかあります。

VAR=$(FUNCTION) || kill -"$(($?&127))" 0

...一つの方法かもしれません。返される内容は、親シェルのプロセスグループに渡す必要がありますFUNCTION。実際には具体化されていませんが、必要に応じてコマンドの置換から簡単に返すことができます。また、現在のシェル関数内で変数の割り当てに関するアドバイスが必要な場合は、次のこともできます。

fn(){ var=x; }; fn; echo "$var"

x

いくつかのコマンドの出力でなければならない場合は、階層的な評価について話しているのです。実際には、その出力を信頼する必要があります。それ以外の場合は、ストリーム全体をキャプチャする必要があります。この場合、その出力をいつ受け取ることができるかを確認することをお勧めします。これらの作業は通常パイプを介して行われます。これはコマンド置換が機能する方法であり、もちろんサブシェルも同様です。シェルと同様に、read他の場所で提案されているようにデータを入力する必要があります。

私は自分の小さなパイプを使用するのが好きです。パイプのバッファに一度に少しずつ書き、準備ができたらもう一度読みます。

fn(){ echo hey; read hey; } <> <(:) >&0
fn; echo "$hey"

hey

...最後の例に従う場合は特に注意する必要があると言及する必要があるようです。いいえバッファを埋めるには。一度に少しずつ書いて、できるだけ早く読んでください。ほとんどすべてのシステムで512バイト(多くはありません)のデフォルトバッファを使用できますが、通常は大きいです。

注意しないと、そのパイプの両端の所有者として、シェルがデッドロックに陥ったときに他のプロセスからイライラした終了信号を受け取ることができず、永遠に停滞します。必要に応じてパイプを空にするためにリーダープロセスを分岐しない限り、組み込まれていないコマンドの出力はこれらのファイル記述子の1つに割り当てられません。

これは同じプロセスメッセージングを困難にする。完全な同期により、慎重に管理し、同時にタスク内のすべての個々のスレッドを追跡する必要があります。これがシェルフォークが発生する理由です。

答え4

私は使用する:

tmp_fifo=$(mktemp)
mkfifo ${tmp_fifo}
exec 5<>${tmp_fifo}

assign() {
  local var=$1;
  shift
  "$@" >&5
  read ${var} <&5
}

assign myVar echo hola
echo $myVar

rm -f ${tmp_fifo}

関連情報