web-dev-qa-db-ja.com

ヒアドキュメントのstdinからの読み取りを使用して変数を定義します

次のように、AvailableメモリとTotalMemoryをスクリプトファイルの変数に保存しようとしています。

_read -r Available Total <<EOT
$(free -m | awk '/^Mem/{print $7; print $2;}')
EOT

$ echo $Total

$ echo $Available
1437
_

しかし、変数$ Totalを格納できません。

しかし、私がそうするとき:

_$ read Available Total <<EOT
$(echo $(free -m | awk '/^Mem/{print $7; print $2;}'))
EOT

$ echo $Available
1309
$ echo $Total
7865
_

できます。しかし、shellcheckは私に次の提案をします:

Useless echo? Instead of 'echo $(cmd)', just use 'cmd'. [SC2005]

なぜ最初の例が機能しなかったのですか?そしてなぜ2番目のものが機能するのですか?

1
Nikhil

そのawkコマンドは2つの値を2つの別々の行に出力し、readは1行を読み取り、その上に2つのフィールドが見つかることを期待します。

printコマンドを_print $7, $2;_に変更して、同じ行に番号を出力します。これにBashのタグを付けたので、here-docの代わりにhere-stringを使用して、コマンド全体を少しすっきりさせることができます。

_$ read -r Available Total <<< $( free -m | awk '/^Mem/{print $7, $2;}' )
_

または、プロセス置換を使用します。

_$ read -r Available Total <   <( free -m | awk '/^Mem/{print $7, $2;}' )
_

コマンド置換を引用符なしでecho $(...)を使用すると、コマンドからの出力はWord分割になり、echoは個別の行を個別の引数として認識します。スペースで結合されたすべての引数を1行に出力します。

echo $(foo)は通常、かなり役に立たないことですが、まさにこの理由から、fooだけでは同じではありません。また、fooの出力の最後に、まだ改行がない場合は、最後の改行を入れます。

4
ilkkachu