Makefileにファイルが存在するかどうかを確認して削除できるようにするにはどうすればよいですか?


135

私のクリーンセクションでは、Makefile完全に削除する前にファイルが存在するかどうかを確認しようとしています。このコードを使用しましたが、エラーが発生します。

どうしたの?

 if [ -a myApp ]
 then
     rm myApp
 fi

このエラーメッセージが表示される

 if [ -a myApp ]
 /bin/sh: Syntax error: end of file unexpected (expecting "then")
 make: *** [clean] Error 2

myAppは変数ですか、それとも実際のファイル名ですか?
BugFinder

myAppはmyApplication、つまりビルドプロセスによるファイル名です。
アブルッツォフォルテeジェンタイル

5
ファイルが存在しない場合に停止を回避したいだけの場合はrm -rf myApp、代替手段になる可能性があります。または、コマンドの前にダッシュ(-rm myApp)を付けて、rmからのエラーを無視させます(ただし、醜いメッセージが出力されます)。
thomasa88 2014年

1
あなたの問題は、makeがルールの各行を個別のコマンドとして扱い、それらを個別にシェルに送信することでした。これは、「if [-a myApp]」を単独で実行するようなものです。このエラーが発生した場合は、行を1つに結合する(を使用して)か、各行が他の行から独立しているという解決策が必要です。現在、これらのいくつかが以下にあります。
Michael

回答:


40

2番目のトップの回答はに言及していますがifeq、これらがターゲットの名前と同じレベルにある必要があることは言及していません。たとえば、現在ファイルが存在しない場合にのみファイルをダウンロードするには、次のコードを使用できます。

download:
ifeq (,$(wildcard ./glob.c))
    curl … -o glob.c
endif

# THIS DOES NOT WORK!
download:
    ifeq (,$(wildcard ./glob.c))
        curl … -o glob.c
    endif

if if fi
Taras Matsyk

3
この答えは少し変です。ファイルチェックはmakefileが処理されるときに行われますが、アクションは後でターゲットがmakeによってビルドされたときに行われます。その間にファイルを削除すると、ファイルは作成されません。わかりやすくするために編集を加えました。
Michael

どうもありがとう!この点はマニュアルを読んでも明らかではなかった。
Kevin Buchs

207

これにシェルスクリプトを使用している人がたくさんいるのは奇妙です。ネイティブのメイクファイル構文を使用する方法を探していました。これは、ターゲットの外側で作成しているためです。wildcard関数を使用して、ファイルが存在するかどうかを確認できます。

 ifeq ($(UNAME),Darwin)
     SHELL := /opt/local/bin/bash
     OS_X  := true
 else ifneq (,$(wildcard /etc/redhat-release))
     OS_RHEL := true
 else
     OS_DEB  := true
     SHELL := /bin/bash
 endif 

更新:

私は本当に私のために働いている方法を見つけました:

ifneq ("$(wildcard $(PATH_TO_FILE))","")
    FILE_EXISTS = 1
else
    FILE_EXISTS = 0
endif

4
これを試してみましたが、取得し続けていますMakefile:133: *** unterminated call to function `wildcard': missing `)'. Stop.
Ant6n 2014

1
ワイルドカードの使用が大きいため、makefile自体で実行できます。きちんとした:)
anoop

3
$(wildcard pattern)実際に何が行われているかを理解するのにも役立ちます。リンクを参照してください
Dan博士、

1
より簡潔:FILE_EXISTS := $(or $(and $(wildcard $(PATH_TO_FILE)),1),0)
cmaster-モニカを

2
cygwinの下でWindowsを実行している場合、注目に値します。この方法でワイルドカードを使用すると、ファイル名で大文字と小文字が区別されるので、ファイルは存在しますが、パスと大文字と小文字が異なる場合は見つかりません。makefile内でこの動作をオーバーライドする方法はないようです。
ロジャーサンダース

59

問題は、コマンドを複数の行に分割する場合です。したがって、\上記のように継続のために行末でを使用するか&&、bash の演算子を使用してすべてを1行で取得できます。

次に、testコマンドを使用して、ファイルが存在するかどうかをテストできます。例:

test -f myApp && echo File does exist

-f file ファイルが存在し、通常のファイルであれば真。

-s file ファイルが存在し、サイズがゼロより大きい場合は真。

またはしない:

test -f myApp || echo File does not exist
test ! -f myApp && echo File does not exist

test等価である[コマンド。

[ -f myApp ] && rm myApp   # remove myApp if it exists

元の例と同じように機能します。

詳細については、help [またはhelp testを参照してください。


4
私は賛成票を投じていただろうが、あなたはそれ-sがの特別なケースであることを警告しなかったexists and has a size greater than zero。書かれた質問はサイズにとらわれないのでtest -e、ファイルまたは-dディレクトリを使用して存在を確認する必要があります。空のファイルは(より良い用語が必要な場合)インジケーター/センチネルとして特に役立ちますmake
underscore_d

提案をありがとう。-f使用する方が一般的であるため、デフォルトで変更されました。
ケノーブ2015

どうすればtestWindowsにアクセスできますか?
thowa 2016

3
これが機能するためには|| true、ファイルが存在しないときにコマンドがtrueを返すように、最後に追加する必要があります。
jcubic 2018年

2
@AndrewMackenzie test -f myApp || CMD、に注意してください||-f失敗する場合-存在しない(||)場合は、コマンドを実行してください。それは意味がありますか?
ケノーブ

50

継続のために行末にバックスラッシュが必要な場合があります(ただし、makeのバージョンによって異なる場合があります)。

if [ -a myApp ] ; \
then \
     rm myApp ; \
fi;

2
Makefileの構文ではないようですか?sunsite.ualberta.ca/Documentation/Gnu/make-3.79/html_chapter/...
ホルムズ

@holmsはbash構文です。新しい行をエスケープすることにより、単一のbashコマンドとして処理することができます。デフォルトではmake、新しい行には新しいbashコマンドがあります。\ 行の終わりにたくさんあることの煩わしさを除いて、これの主な注意点は、すべてのコマンドは、;そうでなければbashで暗黙的であるもので終了しなければならないことです。
flungo 2014

1
正解は@holmsです。「\」もワイルドカードも、この目的のために意図されたものではありません。ワイルドカードを使用する理由は、コードを明確にするためです。このメソッドは読みにくくなるだけでなく、構文エラーが発生しやすくなります。
Maitreya

1
提供されたリンク@holmsは機能しなくなりました。代わりにgnu.org/software/make/manual/make.html#Conditionalsを使用してください
fero

これは優れた回答です。元の質問者がしたことと何が悪いのかが一致し、Makefileの起動時ではなく、ターゲットのビルド時にファイルが存在するかどうかに応じて機能します。ほとんどの時間を欲しがっています。いくつかの奇妙なケースでは、@ cnstからの回答の方が良いでしょう。
Michael

31

それともmake好きなように、それを1行に置くだけです:

if [ -a myApp ]; then rm myApp; fi;

これはこの場合(および賛成投票が必要)の素晴らしい回答ですが、アクションがより複雑な場合はうまく機能しません。その場合、\を使用するように切り替えてください
Michael

[-a myApp] && rm myApp
Robin Hsu

14

セミコロンがない

if [ -a myApp ];
then
  rm myApp
fi

ただし、エラーメッセージを防ぐために、削除する前に存在を確認しているものと思います。その場合、rm -f myAppどの「強制」削除を使用するか、つまり、ファイルが存在しなかった場合でもエラーにならないようにすることができます。


1
ThHatはまさに私がやりたかったことです。どうもありがとう。
アブルッツォフォルテeジェンタイル

1
ifがまだ複数行にまたがっているので、これはMakefileでは機能しません。これを1行に置くか、\ esを使用する必要があります。\ esを追加した場合でも、いくつかのセミコロンがありません。
Michael

13
FILE1 = /usr/bin/perl
FILE2 = /nofile

ifeq ($(shell test -e $(FILE1) && echo -n yes),yes)
    RESULT1=$(FILE1) exists.
else
    RESULT1=$(FILE1) does not exist.
endif

ifeq ($(shell test -e $(FILE2) && echo -n yes),yes)
    RESULT2=$(FILE2) exists.
else
    RESULT2=$(FILE2) does not exist.
endif

all:
    @echo $(RESULT1)
    @echo $(RESULT2)

実行結果:

bash> make
/usr/bin/perl exists.
/nofile does not exist.

これは私を助けてくれました、OPがmakefileについて尋ねているのを見逃した人もいると思います。「&& echo -n yes」が必要な理由がわかりませんでした。説明:test -eが1(見つからない)を返す場合、シェルはechoコマンドを実行しないため、ifeqのyesと一致しません
Brad Dre

説明文で正しく理解できたと思います。
Robin Hsu

@BradDre- echo -n yesの成功をNLなしtestの文字列に変更しyesます。次にifeq、ハードコードされたと比較できyesます。なぜならifeq、シェルコマンドからの成功ステータスではなく、比較する文字列が必要だからです。
ジェシーチザム

8

1行のソリューション:

   [ -f ./myfile ] && echo exists

エラーアクションのある1行のソリューション:

   [ -f ./myfile ] && echo exists || echo not exists

私のmake cleanディレクティブで使用されている例:

clean:
    @[ -f ./myfile ] && rm myfile || true

そしてmake clean常にエラーメッセージなしで動作します!


3
@rm -f myfileを実行してください。「-f」フラグのため、「rm」は、ファイルが存在するかどうかに関係なく、0で終了します。
Alexey Polonsky、2016年

または、-rm myfileエラーを無視するようmakeに指示する先頭ダッシュ。
ジェシーチザム

1
私の場合、|| <エラーアクション>により問題が発生しました。最後の例では、ファイルが存在しない場合にtrueを返しましたが、これは適切に対処されました。ありがとうございました!
フリック

私にとってMYFILEへのパスは、アポストロフィ( ')であることが必要である:@[ -f 'myfile' ] && rm myfile
ステン

0
test ! -f README.md || echo 'Support OpenSource!' >> README.md

「README.mdが存在しない場合は、何もせずに正常に終了します。それ以外の場合は、末尾にテキストを追加します。」

&&代わりにを使用すると||、ファイルが存在しないときにエラーが発生します。

Makefile:42: recipe for target 'dostuff' failed
make: *** [dostuff] Error 1

0

やってみた:

[ -f $(PROGRAM) ] && cp -f $(PROGRAM) $(INSTALLDIR)

そして肯定的なケースはうまくいきましたが、私のubuntu bashシェルはこれをTRUEと呼び、コピーを壊します:

[ -f  ] && cp -f  /home/user/proto/../bin/
cp: missing destination file operand after '/home/user/proto/../bin/'

このエラーが発生した後、ファイルがmakeに存在するかどうかを確認する方法をグーグルで検索しました。これが答えです...


0
ifneq ("$(wildcard $(PATH_TO_FILE))","")
    FILE_EXISTS = 1
else
    FILE_EXISTS = 0
endif

上記のこのソリューションが最も効果的です。ただし、PATH_TO_FILE割り当てを文字列化しないようにしてください。

PATH_TO_FILE = "/usr/local/lib/libhl++.a" # WILL NOT WORK

それは違いない

PATH_TO_FILE = /usr/local/lib/libhl++.a

-2

@ mark-wilkinsのように、\を使用して行を続け、シェルでそれらを終了するか、@ kenorbからのものを同様にこれを1行に変更することは適切であり、この問題を修正します。

(@ alexey-polonskyが指摘したように)元の問題に対するより簡単な答えがあります。-fフラグを使用してrmを実行し、エラーをトリガーしないようにします。

rm -f myApp

これは、よりシンプルで、より高速で、より信頼性があります。スラッシュと空の変数で終わらないように注意してください

rm -f / $(myAppPath) #絶対にしないでください

システムを削除してしまう可能性があります。


1
これは、OPが持っていたファイルを削除するための適切な回答ですが、この質問を見つけたほとんどの人が実際にファイルの削除を探しているわけではないと確信しています。これは、ほとんどの回答rmでまったく言及されていないという事実によって実際に証明されています。ちなみに、はディレクトリであり、が見つからないrm -f /$(myAppPath)ので、これでも何のダメージも与えないと確信しています。/-r
cnst

これは簡単な解決策ではありません。@cnstが言ったように、元の投稿者が単にを実行したくない理由があるかもしれません。rm -fたとえばrm、変数にしたいかもしれません。
Dan Nguyen
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.