1. ホーム
  2. bash

[解決済み] Makefileでシェルコマンドを使用する方法

2022-08-05 03:16:04

質問

の結果を使用しようとしています。 ls の結果を他のコマンド(例:echo、rsync)で使いたいのです。

all:
    <Building, creating some .tgz files - removed for clarity>
    FILES = $(shell ls)
    echo $(FILES)

しかし、私は得る。

make
FILES = Makefile file1.tgz file2.tgz file3.tgz
make: FILES: No such file or directory
make: *** [all] Error 1

を使ってみました。 echo $$FILES , echo ${FILES}echo $(FILES) を使用することができますが、運が悪いことに

どのように解決するのですか?

で。

FILES = $(shell ls)

の下にインデントされた all といった感じで、ビルドコマンドになっています。 つまり、これは $(shell ls) を展開し、次にコマンド FILES ... .

もし FILESmake という変数がある場合、これらの変数はレシピ部分の外側で代入する必要があります、例えば

FILES = $(shell ls)
all:
        echo $(FILES)

もちろん、それはつまり FILES からの出力は "に設定されます。 ls "となります。 の前に を実行する前に、.tgz ファイルを作成するコマンドのいずれかを実行します。 (ただし カズノート は毎回再展開されるので、最終的には .tgz ファイルを含むことになります; いくつかの make のバージョンでは FILES := ... を使うことで、効率や正確さのために、これを避けることができます。 1 )

もし FILES がシェル変数であると仮定した場合、それを設定することはできますが、スペースなしで、引用符で囲まれたシェル言語でそれを行う必要があります。

all:
        FILES="$(shell ls)"

ただし、各行は別々のシェルで実行されるので、この変数は次の行まで生き残らないので、すぐに使用する必要があります。

        FILES="$(shell ls)"; echo $$FILES

これは少し馬鹿げています。 * (および他のシェルのグロブ表現) を展開するので、これは少し馬鹿げています。

        echo *

をシェルコマンドで指定します。

最後に、一般的なルールとして (この例にはあまり当てはまりませんが) エスペラント の出力を使って、コメント中の ls の出力は完全に信頼できるものではありません (いくつかの詳細はファイル名に依存しますし、時には ls のいくつかのバージョンに依存します。 ls は出力のサニタイズを試みる場合があります)。 したがって、次のように l0b0 イデリック 注:GNU make を使っている場合は $(wildcard)$(subst ...) の中ですべてを実現するために make の中ですべてを実現します (ファイル名に変な文字が含まれる問題を回避します)。 (内部 sh スクリプトで、makefile のレシピ部分を含む、もうひとつの方法として find ... -print0 | xargs -0 を使って、空白や改行、制御文字などに引っかからないようにすることです)。


1 GNU Makeのドキュメントでは、さらにPOSIX makeが追加した ::= の割り当てが追加されたことを記しています。 . これに関する POSIX ドキュメントへのクイックリファレンスのリンクは見つかっていませんし、どの make バリアントが ::= の代入をサポートしていますが、今日では GNU make がサポートしています。 := と同じ意味で、つまり、拡張して今すぐ割り当てを実行します。

なお VAR := $(shell command args...) は、次のように表記することもできます。 VAR != command args... のように、いくつかの make の変種があり、私の知る限りでは、最近のすべての GNU と BSD の変種を含みます。 これらの他の変種には $(shell) がないので VAR != command args... を使う方が、より短いという点で優れています。 がより多くのバリエーションで動作するという点で優れています。