web-dev-qa-db-ja.com

Makefileで連想配列のbashを繰り返す

$ bash -version
GNU bash, version 4.3.11(1)-release (x86_64-pc-linux-gnu)

次のシェルスクリプトを考えてみます。

#!/bin/bash

declare -A PROVS=( ["NL"]=10 ["PE"]=11 ["NS"]=12 ["NB"]=13 ["QC"]=24 ["ON"]=35 ["MB"]=46 ["SK"]=47 ["AB"]=48 ["BC"]=59 ["YK"]=60 ["NT"]=61 ["NU"]=62 )

for key in "${!PROVS[@]}" ; do \
  touch "foo_${key}_${PROVS[${key}]}" ; \
done

私はMakefileで同等のものをやろうとしています:

Shell := /bin/bash
.PHONY: foo
foo:
  declare -A PROVS=( ["NL"]=10 ["PE"]=11 ["NS"]=12 ["NB"]=13 ["QC"]=24 ["ON"]=35 ["MB"]=46 ["SK"]=47 ["AB"]=48 ["BC"]=59 ["YK"]=60 ["NT"]=61 ["NU"]=62 )

  for key in "$${!PROVS[@]}" ; do \
    touch "foo_$${key}_$${PROVS[$${key}]}" ; \
  done

ファイルをtouchしたくありません本当に; @echoを実行できないため、これを行っています。ループにいるため、@が行の先頭にあるとは見なされません。またはそれが起こっているようです。

とにかく、ポイントは、ループがまったく実行されていないように見えるため、touch/echoビジネスです。上記のシェルスクリプトの内容は、makeがターミナルにエコーするものとまったく同じです。私はシバンを追加して、それを健全性チェックとして実行しました-魅力のように機能します。

通常の配列を使用するとうまくいきます:

for prov in NL PE NS NB QC ON MB SK AB BC YK NT NU ; do \

ただし、これらのコード(10、11など)も必要です。

誰かこれについて洞察がありますか?

必須ではありませんが、「declare -A」を使用しながら、ファイルの先頭にPROVS変数を割り当てる方法(または可能であれば)も知りたいです。

編集:インラインシェルコマンドの一部にすぎないようにMakefileの例を台無しにしたので、もはやレシピではありません。明確にするために、「foo:」ターゲットを再度追加しました。

5
brian

コードの抜粋が適切に表現されている場合、Makefileに直接Bashコマンドを入力しており、MakeがBashでそれらを実行することを期待しているようです。それはそれがどのように機能するかではありません。 Makefileの構文は完全に異なります。 レシピ内で、Bashコマンドを入力できます。レシピの個別の各行は、個別のサブシェルで実行されます。したがって、少なくとも2つの変更が必要です。

  • シェルコマンドはターゲット内にある必要があります。
  • declareはループと同じシェルで実行する必要があります。それ以外の場合は、1つのBashインスタンスでdeclareを実行し、それを終了してから、失われたdeclareについて何も認識していない別のインスタンスでループを実行します。

以下は、これらの変更を加えたMakefileの簡単なリファクタリングです。

Shell=/bin/bash   # This is the standard compliant method

.PHONY: all
all:
    declare -A PROVS=( ["NL"]=10 ["PE"]=11 ["NS"]=12 ["NB"]=13 \
        ["QC"]=24 ["ON"]=35 ["MB"]=46 ["SK"]=47 ["AB"]=48 \
        ["BC"]=59 ["YK"]=60 ["NT"]=61 ["NU"]=62 )\
    ; for key in "$${!PROVS[@]}" ; do \
        touch "foo_$${key}_$${PROVS[$${key}]}" ; \
    done

デモ: http://ideone.com/t94AOB

コマンドをサイレントに実行するための@規則は、コマンドライン全体に適用されます。したがって、上のdeclareの前に置くことができます。その場合、コマンドライン全体がBashに送信される前に削除されます。それ以外の場所では、それは取り除かれたり理解されたりせず、呼び出されたシェルで明らかにBash構文エラーを引き起こします。

@ルールへの執着はとにかく反パターンです。出力を表示したくない場合はmake -sで実行してください。makeをシャットダウンするとデバッグが難しくなりますあなたのルール。)

6
tripleee