パイプの出力を変数に取得しようとしています。私は次のことを試しました:
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)
コマンド置換を使用します。
myvar=`echo foo`
または
myvar=$(echo foo)
正しい解決策は、次のようなコマンド置換を使用することです。
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"
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<<< ''