Dosyayı silebilmek için Makefile'de dosyanın olup olmadığını nasıl kontrol edebilirim?


135

Benim temiz bölümünde Makefilekalıcı olarak silmeden önce dosyanın var olup olmadığını kontrol etmeye çalışıyorum. Bu kodu kullanıyorum ama hata alıyorum.

Bunun nesi var?

 if [ -a myApp ]
 then
     rm myApp
 fi

Bu hata mesajını alıyorum

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

MyApp bir değişken mi yoksa gerçek bir dosya adı mı?
BugFinder

myApp, myApplication, yani derleme işleminin dosya adı içindir.
Abruzzo Forte e Gentile

5
Sadece dosya yoksa durmaktan kaçınmak istiyorsanız, rm -rf myAppalternatif olabilir. Veya -rm myApprm'den gelen hatayı göz ardı etmek için komuttan önce bir tire ( ) koyun (ancak çirkin bir mesaj yazdırır).
thomasa88

1
Sorununuz, bir kuraldaki her satıra ayrı bir komut olarak davranması ve bunları kabuğa ayrı ayrı göndermesidir. Tek başına `` [-a myApp] '' çalıştırmak gibi bir şey. Bu hatayı alırsanız, çizgileri bir (birleştiren) birleştiren veya her bir çizgiden diğerinden bağımsız olan bir çözüme ihtiyacınız vardır. Şimdi bunlardan birkaç tane var.
Michael

Yanıtlar:


40

ifeqBununla birlikte, en üstteki ikinci yanıt , bunların hedefin adıyla aynı düzeyde olması gerektiğinden bahsetmez, örneğin, bir dosyayı yalnızca şu anda mevcut değilse indirmek için aşağıdaki kod kullanılabilir:

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 sonra
Taras Matsyk

3
Bu cevap biraz garip olacak; dosya denetimi, makefile işlendiğinde gerçekleşir, ancak eylem daha sonra hedef make tarafından oluşturulduğunda gerçekleşir. Bu arada dosyayı silerseniz, dosya oluşturulmaz. Daha anlaşılır olması için bir düzenleme yaptım.
Michael

Çok teşekkürler! Bu nokta kılavuzu okumaktan net değildi.
Kevin Buchs

207

Bunun için kabuk komut dosyası kullanan birçok insanı görmek garip. Yerel makefile sözdizimini kullanmanın bir yolunu arıyordum, çünkü bunu herhangi bir hedefin dışında yazıyorum. wildcardDosyanın var olup olmadığını kontrol etmek için işlevi kullanabilirsiniz :

 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 

Güncelleme:

Benim için gerçekten işe yarayan bir yol buldum:

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

4
bunu denedim, ama sadece almaya devamMakefile:133: *** unterminated call to function `wildcard': missing `)'. Stop.
Ant6n

1
Joker karakterin büyük kullanımı, bu nedenle makefile'in kendisi ile yapılabilir. Temiz :)
anoop

3
$(wildcard pattern)Gerçekte ne yaptığını anlamaya da yardımcı olur . Bkz. Bağlantı .
Dr. Dan

1
Daha özlü:FILE_EXISTS := $(or $(and $(wildcard $(PATH_TO_FILE)),1),0)
cmaster - monica

2
Cygwin altında Windows üzerinde çalışıp çalışmadığınızı belirtmek gerekir, bu şekilde joker karakter kullanmak dosya adında büyük / küçük harfe duyarlı bir eşleşme yapar, bu nedenle dosya varsa ancak yoldan farklı bir durumda bulunamaz. Bu dosyada makefile geçersiz kılmanın bir yolu yok gibi görünüyor.
Roger Sanders

59

Sorun, komutunuzu birden çok satıra bölmenizdir. Yani, \yukarıdaki gibi devam etmek için satırların sonundaki ya da her şeyi bir satırda&& bash operatörüyle .

Sonra testdosyanın var olup olmadığını test etmek için bir komut kullanabilirsiniz , örneğin:

test -f myApp && echo File does exist

-f file Dosya varsa ve normal bir dosyaysa doğrudur.

-s file Dosya varsa ve boyutu sıfırdan büyükse doğrudur.

ya da yapmaz:

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

Bu test, [komuta eşdeğerdir .

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

ve orijinal örneğinizdeki gibi çalışır.

Bkz: help [ya help testbaşka sözdizimi için.


4
Ben iptal edecektim, ama -sbunun için özel bir durum olduğu konusunda uyarmadınız exists and has a size greater than zero. Yazıldığı gibi soru boyutsal-agnostiktir, bu nedenle varlığın test -ebir dosya veya -ddizin için kontrol edilmesi gerekir . Boş dosyalar özellikle (daha iyi bir terim istemek için) göstergeler / nöbetçiler olarak oldukça yararlı olabilir make.
underscore_d

Önerin için teşekkürler. -fKullanımı daha yaygın olduğu için varsayılan olarak değiştirildi .
kenorb

testWindows'a nasıl erişebilirim ?
thowa

3
Bunun çalışması || trueiçin sonuna dosya eklemeniz gerekir .
jcubic

2
@AndrewMackenzie test -f myApp || CMD, dikkat edin ||, eğer -fbaşarısız olursa - mevcut değil ( ||), sonra komutu çalıştırın. Mantıklı geliyor?
kenorb

50

Devam etmek için hattın sonunda ters eğik çizgi gerekebilir (belki de bu, markanın sürümüne bağlıdır):

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


@holms bir bash sözdizimidir. Yeni satırlardan kaçarak, tek bir bash komutu olarak ele alınmasını sağlar. Varsayılan olarak makeyeni bir satırda yeni bir bash komutu olur. Bunun en büyük uyarısı, \ satırların sonunda çok fazla olmanın sıkıntısı dışında, her komutun ;aksi halde bash'da örtük olacak şekilde sonlandırılması gerektiğidir .
flungo

1
Doğru cevap @holms. Ne '\' ne de joker karakter tam olarak bu amaç için tasarlanmamıştır. Joker karakter kullanmanızın nedeni kod netliği içindir. Bu yöntem yalnızca daha az okunabilir değil, sözdizimi hatalarına daha yatkındır.
Maitreya

1
sağlanan bağlantı @holms, artık kullanım çalışmıyor gnu.org/software/make/manual/make.html#Conditionals yerine
fero

bu harika bir cevaptır, çünkü orijinal sorgulayıcının yaptığıyla neyin yanlış olduğunu eşleştirir ve çoğu insanın beklediği Makefile'nin başlatıldığı zaman değil, hedefin oluşturulduğu sırada dosyanın var olup olmadığına bağlı olarak çalışır. ve çoğu zaman istiyorum. Birkaç garip durumda @ cnst'in cevabı daha iyi olurdu.
Michael

31

Veya sadece bir satıra koyun, makebeğendiği gibi:

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

Bu, bu durumda harika bir cevap (ve upvotes almalı) ama eylemler daha karmaşık olsaydı çok iyi çalışmaz, bu durumda \
Michael

[-a myApp] && rm myApp
Robin Hsu

14

Noktalı virgül eksik

if [ -a myApp ];
then
  rm myApp
fi

Ancak, bir hata mesajını önlemek için silmeden önce varlığını kontrol ettiğinizi varsayalım. Öyleyse, yalnızca rm -f myApp"zorla" silmeyi kullanabilirsiniz, yani dosya yoksa hata vermez.


1
ThHat tam olarak yapmak istediğim şeydi. Çok teşekkürler.
Abruzzo Forte e Gentile

1
Bu bir Makefile'da çalışmaz, çünkü if hala birden çok satıra yayılır - bunu bir satıra koymanız veya \ es kullanmanız gerekir. \ es ekleseniz bile hala bazı noktalı virgül eksik.
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)

yürütme sonuçları:

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

Bu bana yardımcı oldu, sanırım bazıları OP'nin makefile hakkında sorduğunu kaçırdı. "&& echo -n yes" neden gerekli olduğunu anlamadım. Açıklama: test -e 1 döndürürse (bulunamadı), shell echo komutunu yürütmez ve bu nedenle ifeq'de yes ile eşleşmez
Brad Dre

Bence açıklama açıklamasında doğru anladın.
Robin Hsu

@BradDre - NL olmadan dizenin echo -n yesbaşarısını değiştirir . Kutu daha sonra sabit kodlu ile karşılaştırabilir . Çünkü kabuk komutunun başarı durumunu değil, bir dizenin karşılaştırılmasını ister. testyesifeqyesifeq
Jesse Chisholm

8

Tek hat çözümü:

   [ -f ./myfile ] && echo exists

Hata işlemiyle tek satırlık çözüm:

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

make cleanYönergelerimde kullanılan örnek :

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

Ve make cleanher zaman hata mesajı olmadan çalışır!


3
sadece @rm -f dosyam. "-F" bayrağı nedeniyle, "rm" dosyanın var olup olmadığına bakılmaksızın 0 ile çıkar.
Alexey Polonsky

Ya da, -rm myfilesatır aralığı söylentisi herhangi bir hatayı yok saymayı sağlar.
Jesse Chisholm

1
Benim durumumda || <hata eylemi> sorunlara neden oldu. Dosya mevcut değilse true değerini döndürdüğünüz son örneğiniz bunu güzel bir şekilde ele aldı. Teşekkür ederim!
Flic

Benim için dosyamın kesme işareti (') ile olması gerekiyor:@[ -f 'myfile' ] && rm myfile
Sten

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

"README.md yoksa, hiçbir şey yapmayın (ve başarıyla çıkın). Aksi takdirde, sonuna metin ekleyin."

Eğer kullanırsanız &&yerine ||dosya yok olduğunda o zaman bir hata oluşturabilir:

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

0

Deniyordum:

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

Ve olumlu dava çalıştı ama benim ubuntu bash kabuğu bu DOĞRU çağırır ve kopya kopar:

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

Bu hatayı aldıktan sonra, google bir dosyanın var olup olmadığını kontrol etmek nasıl ve bu cevap ...


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

Yukarıda yayınlanan bu çözüm en iyi sonucu verir. Ancak PATH_TO_FILE atamasını dizgelemediğinizden emin olun. Örn.

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

Olmalı

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

-2

@ Mark-wilkins'den gelen cevaplar gibi devam etmek için \ ile satırları ve; onları kabukta sonlandırmak veya @kenorb'dan bir satır olarak değiştirmek gibi olanlar iyi ve bu sorunu çözecektir.

orijinal soruna daha basit bir cevap var (@ alexey-polonsky'nin işaret ettiği gibi). -M bayrağını kullanarak rm hatası vererek tetiklemeyin

rm -f myApp

bu daha basit, daha hızlı ve daha güvenilirdir. Sadece bir eğik çizgi ve boş bir değişkenle sonuçlanmamaya dikkat edin

rm -f / $ (myAppPath) #Bunu ASLA YAPMAYIN

sonunda sisteminizi silebilirsiniz.


1
Bu, OP'nin sahip olduğu dosyayı silmek için iyi bir yanıttır, ancak eminim ki bu soruyu bulan çoğu kişi herhangi bir dosyayı silmek istemiyor; bu aslında cevapların çoğunun hiç bahsetmediği gerçeğiyle kanıtlanmıştır rm; BTW, rm -f /$(myAppPath)herhangi bir zarar vermeyeceğinden eminim , çünkü /bir dizin ve -reksik.
cnst

Bu daha basit bir çözüm değil. @Cnst'in dediği gibi, orijinal posterin sadece bir yapmak istemediğinin nedenleri olabilir rm -f, örneğin rmbir değişkeni isteyebilirler .
Dan Nguyen
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.