Makefile、組み込みの角かっこ、変数の拡張、コマンドの置換

Makefile、組み込みの角かっこ、変数の拡張、コマンドの置換

DRY(反復しないでください)原則に従うためには、次のことを行う必要があります。ファイルの生成。したがって、そのファイルのどこかに次のレシピがあります。

shell=/bin/bash
# …
.ONESHELL:
run:
    # Create bash sub-shell «cmd» var, holding a built-in test as a string
    @cmd='[ $$(grep -iE _dev </etc/hosts | wc -l) -eq 0 ]'
    # "$$" tells make to escape the dollar sign. So echoing …
    @echo "$$cmd"
    # gives «[ $(grep -iE _dev </etc/hosts | wc -l) -eq 0 ]» as I expected
    # I need this variable to be expanded and interpreted as a real
    # built-in square bracket test, so I wrote
    @$$cmd && echo "Pass ! do more magical things …" || true

私は期待作るエスケープ$記号$$cmd$cmdが再び表示されます。強く打つ引用符で囲まれていない文字列をテストするには、コンテキストを括弧内に入れます。そうなんですか?
しかし、エラーが発生しました。/bin/bash: line 2: [: too many arguments

このエラーが発生する理由を知っている人はいますか?
Bashが私が期待するブラケットテストを提供しないのはなぜですか?
[ $(grep -iE _dev </etc/hosts | wc -l) -eq 0 ] && echo "Pass!"

ありがとうございます。

答え1

シェルの変数とコマンドの置換は、コマンド境界が決定され、リダイレクト(および割り当て)が解析された後に発生します。プログラム名および/またはパラメータを変数に入れて置き換えることはできますが、パイプ、リダイレクト、割り当て、またはシェル$( command )キーワード(およびif)などの他の代替エントリは使用できませんfor

この場合、コマンドを変更してテストを反転して交換して、パイプとトイレを取り外すことができます。

cmd='grep -qi _dev /etc/hosts' # note file as argument not redirection
$$cmd || do_blah

置換されたgrepコマンドは、ファイル内の一致するものが見つからないと自動的に失敗し、失敗するとdo_blahを実行します。

通常、値(プログラムパラメータだけでなく)を置き換えるときにシェル構文を使用するには、それを使用して値(または値)置換を実行するか(必要に応じて環境および/またはコマンド置換に応じて)evalサブシェルを実行する必要があります。sh -c "$$cmd"他のシェル))。

答え2

AはMakefileシェルスクリプトではありません。すべての内容を次のように、よりシンプルできれいに作成できます。

#!/bin/sh
set -e
grep -q -iE _dev /etc/hosts
echo pass
...

関連情報