web-dev-qa-db-ja.com

Bash:パイプの出力を変数に割り当てます

パイプの出力を変数に取得しようとしています。私は次のことを試しました:

echo foo | myvar=$(</dev/stdin)
echo foo | myvar=$(cat)
echo foo | myvar=$(tee)

だが $myvarは空です。

したくない:

myvar=$(echo foo)

サブシェルをスポーンしたくないからです。

何か案は?

編集:パイプの前のコマンドがグローバル変数を編集する必要があるため、サブシェルでは実行できないため、サブシェルを生成したくありません。それをできる? echoは単純化のためです。それはもっと似ています:

complex_function | myvar=$(</dev/stdin)

そして、それがうまくいかない理由はわかりません。これは例えば機能します:

complex_function | echo $(</dev/stdin)
9
Parckwart

コマンド置換を使用します。

myvar=`echo foo`

または

myvar=$(echo foo)
8
Zumo de Vidrio

正しい解決策は、次のようなコマンド置換を使用することです。

variable=$(complex_command)

のように

message=$(echo 'hello')

(つまり、この場合はmessage=hello)。

あなたのパイプライン:

echo 'hello' | message=$(</dev/stdin)

または

echo 'hello' | read message

実際に動作します。唯一の問題は、使用しているシェルがパイプラインの2番目の部分をサブシェルで実行することです。このサブシェルはパイプラインが終了すると破棄されるため、$messageの値はシェルに保持されません。

ここでそれが機能することがわかります:

$ echo 'hello' | { read message; echo "$message" }
hello

...しかし、サブシェルの環境は分離されている(そしてなくなった)ので:

$ echo "$message"

(出力なし)

あなたのための1つの解決策は、これについてより賢いksh93に切り替えることです:

$ echo 'hello' | read message
$ echo "$message"
hello

bashのもう1つの解決策は、lastpipeシェルオプションを設定することです。これにより、パイプラインの最後の部分が現在の環境で実行されます。ただし、lastpipeはジョブ制御がアクティブでないことを要求するため、これはインタラクティブシェルでは機能しません。

#!/bin/bash

shopt -s lastpipe
echo 'hello' | read message
echo "$message"
8
Kusalananda

ksh93では、以下を使用できます。

var=${
  my command that updates global variable
}

これは、サブシェルを生成しないコマンド置換の形式です。組み込みコマンドであるコマンドの場合、パイプに出力を書き込むのではなく(デッドロックを回避するためにパイプで読み取りと書き込みを行うためにさまざまなプロセスが必要です)、ksh93は単に出力しないようにします拡張を構成するためにそれらが出力していたであろうものを集める以外に。

$ ksh -c 'a=${ b=123; echo foo;}; echo "$a $b"'
foo 123

fishのコマンド置換も次のように動作します。

$ fish -c 'set a (set b 123; echo foo); echo $a $b'
foo 123

他のほとんどのシェルでは、一時ファイルを使用します。

my command that updates global variable > file
var=$(cat file) # can be optimised to $(<file) with some shells

Linuxでは、bashまたはzsh<<<に一時ファイルを使用する)を使用すると、次のことができます。

{ my command that updates global variable > /dev/fd/3 &&
  var=$(cat<&3); } 3<<< ''
3