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

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)

答え1

正しい回避策は、次のコマンド置換を使用することです。

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"

(出力なし)

ksh931つのソリューションは、よりスマートなソリューションに切り替えることです。

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

別の解決策はシェルオプションをbash設定することです。lastpipeこれにより、パイプラインの最後の部分が現在の環境で実行されます。ただし、lastpipeジョブ制御を有効にしてはいけないため、対話型シェルでは機能しません。

#!/bin/bash

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

答え2

コマンド置換の使用:

myvar=`echo foo`

または

myvar=$(echo foo)

答え3

グローバル変数を変更してその内容をstdoutに印刷する関数が与えられた場合:

global_variable=old_value
myfunction() {
  global_variable=new_value
  echo some output
}

ksh93mksh R45以降では、次のものを使用できます。

var=${
  myfunction
}

それから:

$ print -r -- "$global_variable, $var"
new_value, some output

${ ...; }サブシェルを生成しないコマンド代替形式。組み込みコマンドの場合、出力をパイプに書き込むのではなく(これを行うには、デッドロックを避けるためにパイプで読み書きする他のプロセスが必要です)、ksh93何も出力せずに内容を収集してエクスポートしました。拡張のために登場しました。mksh代わりに一時ファイルを使用してください。

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

fishコマンドの代替動作もksh93に似ています${ ...; }

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

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

myfunction > file
var=$(cat file) # can be optimised to $(<file) with some shells

Linuxでは、bash4.4以前のバージョンを使用するかzsh(一時ファイルを使用<<<)、次のことができます。

{
  myfunction > /dev/fd/3 &&
  var=$(cat<&3)
} 3<<< ''

では、zsh次のこともできます。

() {
   myfunction > $1
   var=$(<$1)
} =(:)

ksh、zsh、bashなどのKorn様シェルでは、$(cmd...)標準形式またはバリアント$(<file)のコマンド置換${ cmd...; }はすべての末尾の改行文字(fileまたは出力cmd)を削除します。バラよりシェル: コマンド置換で末尾の改行 ('\n') を保持します。この問題を解決する方法を学びます。

で、出力の各行を配列のfish個々の要素に割り当てます。出力または 。バージョン 3.4.0 以降、Korn シェルの動作と同様の動作 (末尾の改行をすべて削除) もサポートされます。set var (cmd)cmd$var$varcmdfoofoo<newline>fishset var "$(cmd)"

答え4

一時ファイルを使用して複雑な関数の結果を保存し、処理のために一時ファイルから値を読み取ります。

# Create a temp file for storage
tmppath=$(mktemp)
# run the command and get the output to the temp file
complex_command > "${tmppath}"
# read the file into variable
message=$(cat "${tmppath}")
# use the variable
echo "$message"

rm -f "${tmppath}"

利用方法mktempを参照してくださいシェルスクリプトで一時ファイルを作成するには?

関連情報