Bagaimana cara memeriksa apakah file ada di Makefile sehingga saya dapat menghapusnya?

135

Di bagian bersih saya, Makefilesaya mencoba memeriksa apakah file ada sebelum menghapus secara permanen. Saya menggunakan kode ini tetapi saya menerima kesalahan.

Apakah ada yang salah?

 if [ -a myApp ]
 then
     rm myApp
 fi

Saya mendapatkan pesan kesalahan ini

 if [ -a myApp ]
 /bin/sh: Syntax error: end of file unexpected (expecting "then")
 make: *** [clean] Error 2
Abruzzo Forte e Gentile
sumber
Apakah myApp variabel atau nama file aktual?
BugFinder
myApp adalah untuk aplikasi saya yaitu nama file oleh proses membangun.
Abruzzo Forte e Gentile
5
Jika Anda hanya ingin menghindari berhenti jika file tidak ada, rm -rf myAppbisa jadi alternatif. Atau mendahului perintah dengan tanda hubung ( -rm myApp) untuk membuat abaikan kesalahan dari rm (namun akan mencetak pesan yang jelek).
thomasa88
1
Masalah Anda adalah membuat memperlakukan setiap baris dalam aturan sebagai perintah terpisah dan mengirimkannya secara individual ke shell. Ini seperti menjalankan hanya `if [-a myApp] 'sendiri. Jika Anda mendapatkan kesalahan ini, Anda memerlukan solusi yang menggabungkan garis-garis menjadi satu (menggunakan) atau yang berakhir dengan masing-masing garis independen dari yang lain. Sekarang ada beberapa di bawah ini.
Michael

Jawaban:

40

Namun jawaban atas kedua menyebutkan ifeq, gagal menyebutkan bahwa ini harus pada tingkat yang sama dengan nama target, misalnya, untuk mengunduh file hanya jika tidak ada saat ini, kode berikut dapat digunakan:

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

# THIS DOES NOT WORK!
download:
    ifeq (,$(wildcard ./glob.c))
        curl … -o glob.c
    endif
cnst
sumber
tidak bekerja sampai saya menambahkan backslash `` setelah if fi
Taras Matsyk
3
Jawaban ini akan sedikit aneh; pemeriksaan file terjadi ketika makefile diproses tetapi tindakan akan terjadi nanti ketika target dibangun oleh make. Jika Anda menghapus file sementara itu maka file tidak akan dibuat. Saya telah mengedit agar lebih jelas.
Michael
Terimakasih banyak! Poin ini tidak jelas dari membaca manual.
Kevin Buchs
207

Sungguh aneh melihat begitu banyak orang menggunakan skrip shell untuk ini. Saya sedang mencari cara untuk menggunakan sintaks makefile asli, karena saya menulis ini di luar target apa pun. Anda dapat menggunakan wildcardfungsi ini untuk memeriksa apakah file ada:

 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 

Memperbarui:

Saya menemukan cara yang benar-benar berfungsi untuk saya:

ifneq ("$(wildcard $(PATH_TO_FILE))","")
    FILE_EXISTS = 1
else
    FILE_EXISTS = 0
endif
holms
sumber
4
mencoba ini, tapi saya tetap mendapatkanMakefile:133: *** unterminated call to function `wildcard': missing `)'. Stop.
Ant6n
1
Penggunaan wildcard hebat, sehingga bisa dilakukan dengan makefile sendiri. Rapi :)
anoop
3
Membantu juga memahami apa yang $(wildcard pattern)sebenarnya dilakukan. Lihat tautan .
Dr. Dan
1
Lebih ringkas:FILE_EXISTS := $(or $(and $(wildcard $(PATH_TO_FILE)),1),0)
cmaster - mengembalikan monica
2
Perlu dicatat jika Anda menjalankan pada Windows di bawah cygwin, menggunakan wildcard dengan cara ini cocok dengan huruf besar-kecil pada nama file, jadi jika file ada tetapi dengan case berbeda dari path itu tidak akan ditemukan. Tampaknya tidak ada cara untuk menimpa perilaku ini di dalam makefile.
Roger Sanders
59

Masalahnya adalah ketika Anda membagi perintah Anda ke beberapa baris. Jadi, Anda bisa menggunakan \akhir baris untuk kelanjutan seperti di atas atau Anda bisa mendapatkan semuanya di satu saluran dengan &&operator di bash.

Kemudian Anda dapat menggunakan testperintah untuk menguji apakah file itu ada, misalnya:

test -f myApp && echo File does exist

-f file Benar jika file ada dan merupakan file biasa.

-s file Benar jika file ada dan memiliki ukuran lebih besar dari nol.

atau tidak:

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

Itu testsama dengan [perintah.

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

dan itu akan bekerja seperti pada contoh asli Anda.

Lihat: help [atau help testuntuk sintaksis lebih lanjut.

kenorb
sumber
4
Saya akan diputuskan, tetapi Anda tidak memperingatkan bahwa -sini adalah kasus khusus untuk exists and has a size greater than zero. Pertanyaan yang ditulis adalah size-agnostik, jadi keberadaannya harus diperiksa menggunakan test -efile atau -ddirektori. File kosong dapat sangat berguna sebagai (untuk menginginkan istilah yang lebih baik) indikator / sentinel, yang mungkin cukup relevan untuk make.
underscore_d
Terima kasih untuk sarannya. Diubah -fsecara default, karena lebih umum digunakan.
kenorb
Bagaimana saya bisa mendapatkan testdi Windows?
thowa
3
Agar ini berfungsi, Anda perlu menambahkan || truedi bagian akhir sehingga perintah mengembalikan true ketika file tidak ada.
jcubic
2
@AndrewMackenzie test -f myApp || CMD, perhatikan ||, jadi jika -fakan gagal - tidak ada ( ||), maka jalankan perintah. Apakah masuk akal?
kenorb
50

Mungkin perlu garis miring terbalik pada akhir baris untuk kelanjutan (walaupun mungkin itu tergantung pada versi make):

if [ -a myApp ] ; \
then \
     rm myApp ; \
fi;
Mark Wilkins
sumber
2
tampaknya bukan sintaks Makefile? sunsite.ualberta.ca/Documentation/Gnu/make-3.79/html_chapter/…
holms
@holms dengan sintaks bash. Dengan keluar dari baris baru, ini memungkinkan untuk ditangani sebagai perintah bash tunggal. Secara default di makebaris baru akan menjadi perintah bash baru. Peringatan utama ini, selain gangguan memiliki banyak \ pada akhir baris adalah bahwa setiap perintah harus diakhiri dengan ;yang jika tidak akan tersirat dalam bash.
flungo
1
Jawaban yang benar adalah dengan @holms. Baik '\' maupun wildcard persis ditujukan untuk tujuan ini. Alasan mengapa Anda akan menggunakan wildcard adalah untuk kejelasan kode. Metode ini tidak hanya kurang dapat dibaca, tetapi lebih rentan terhadap kesalahan sintaksis.
Maitreya
1
tautan @holms yang disediakan tidak berfungsi lagi, gunakan gnu.org/software/make/manual/make.html#Conditionals sebaliknya
fero
ini adalah jawaban yang bagus karena cocok dengan apa yang salah dengan apa yang dilakukan oleh penanya asli dan itu akan bekerja tergantung pada apakah file itu ada pada saat target dibangun daripada pada saat Makefile dimulai yang adalah apa yang kebanyakan orang harapkan dan ingin sebagian besar waktu. Dalam beberapa kasus aneh, jawaban dari @cnst akan lebih baik.
Michael
31

Atau cukup letakkan di satu baris, seperti yang makediinginkan

if [ -a myApp ]; then rm myApp; fi;
Jeroen
sumber
itu jawaban yang bagus dalam kasus ini (dan harus mendapatkan upvotes) tetapi tidak akan bekerja dengan baik jika tindakannya lebih kompleks, dalam hal ini hanya beralih menggunakan \
Michael
[-a myApp] && rm myApp
Robin Hsu
14

Kehilangan titik koma

if [ -a myApp ];
then
  rm myApp
fi

Namun, saya berasumsi Anda sedang memeriksa keberadaan sebelum penghapusan untuk mencegah pesan kesalahan. Jika demikian, Anda bisa menggunakan rm -f myApp"kekuatan" yang dihapus, yaitu tidak kesalahan jika file tidak ada.

drysdam
sumber
1
Itulah yang ingin saya lakukan. Terima kasih banyak.
Abruzzo Forte e Gentile
1
ini tidak akan berfungsi di Makefile karena jika masih tersebar di beberapa baris - Anda harus meletakkan ini di satu baris atau menggunakan \ es. dan bahkan jika Anda menambahkan es Anda masih kehilangan beberapa titik koma.
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)

hasil eksekusi:

bash> make
/usr/bin/perl exists.
/nofile does not exist.
Robin Hsu
sumber
Ini membantu saya, saya pikir beberapa merindukan OP bertanya tentang makefile. Saya tidak mengerti mengapa "&& echo -n ya" diperlukan. Penjelasan: jika test -e mengembalikan 1 (tidak ditemukan) maka shell tidak akan menjalankan perintah echo, dan karena itu tidak akan cocok dengan yes di ifeq
Brad Dre
Saya pikir Anda memahaminya dengan benar dalam pernyataan penjelasan Anda.
Robin Hsu
@BradDre - Mengubah echo -n yeskesuksesan testmenjadi string yestanpa NL. Kemudian ifeqdapat membandingkannya dengan kode keras yes. Semua karena ifeqingin membandingkan string, bukan status sukses dari perintah shell.
Jesse Chisholm
8

Solusi satu baris:

   [ -f ./myfile ] && echo exists

Solusi satu baris dengan tindakan kesalahan:

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

Contoh yang digunakan dalam make cleanarahan saya :

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

Dan make cleanselalu berfungsi tanpa pesan kesalahan!

Antonio Feitosa
sumber
3
lakukan saja @rm -f myfile. Karena bendera "-f", "rm" akan keluar dengan 0 terlepas dari apakah file tersebut ada atau tidak.
Alexey Polonsky
Atau, -rm myfileperintah dash dasbor membuat untuk mengabaikan kesalahan.
Jesse Chisholm
1
Dalam kasus saya, meninggalkan || <error action> menyebabkan masalah. Contoh terakhir Anda, di mana Anda mengembalikan true jika file itu tidak ada, ditangani dengan baik. Terima kasih!
Flic
Bagi saya jalan menuju myfile perlu dengan tanda kutip ('):@[ -f 'myfile' ] && rm myfile
Sten
0
test ! -f README.md || echo 'Support OpenSource!' >> README.md

"Jika README.md tidak ada, jangan lakukan apa-apa (dan keluar dengan sukses). Jika tidak, tambahkan teks ke akhir."

Jika Anda menggunakan &&alih-alih ||maka Anda menghasilkan kesalahan saat file tidak ada:

Makefile:42: recipe for target 'dostuff' failed
make: *** [dostuff] Error 1
Matt Janssen
sumber
0

Saya mencoba:

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

Dan kasing positif bekerja tetapi bash shell ubuntu saya menyebut ini BENAR dan merusak salinan:

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

Setelah mendapatkan kesalahan ini, saya google cara memeriksa apakah ada file di make, dan ini adalah jawabannya ...

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

Solusi yang diposting di atas berfungsi paling baik. Tetapi pastikan bahwa Anda tidak menetapkan tugas PATH_TO_FILE Misalnya,

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

Pasti begitu

PATH_TO_FILE = /usr/local/lib/libhl++.a
Om Narasimhan
sumber
-2

Jawabannya seperti dari @ mark-wilkins menggunakan \ untuk melanjutkan baris dan; untuk menghentikan mereka di shell atau seperti yang dari @kenorb mengubah ini ke satu baris adalah baik dan akan memperbaiki masalah ini.

ada jawaban yang lebih sederhana untuk masalah aslinya (seperti yang ditunjukkan @ alexey-polonsky). Gunakan flag -f untuk rm sehingga tidak akan memicu kesalahan

rm -f myApp

ini lebih sederhana, lebih cepat dan lebih dapat diandalkan. Berhati-hatilah agar tidak berakhir dengan garis miring dan variabel kosong

rm -f / $ (myAppPath) # TIDAK PERNAH MELAKUKAN INI

Anda mungkin akhirnya menghapus sistem Anda.

Michael
sumber
1
Ini adalah jawaban yang bagus untuk menghapus file yang dimiliki OP, tetapi saya cukup yakin sebagian besar orang yang menemukan pertanyaan ini sebenarnya tidak mencari untuk menghapus file apa pun; ini sebenarnya dibuktikan oleh fakta bahwa sebagian besar jawaban bahkan tidak menyebutkan rmsama sekali; BTW, saya cukup yakin itu rm -f /$(myAppPath)tidak akan merusak, karena itu /adalah direktori, dan -rhilang.
cnst
Ini bukan solusi yang lebih sederhana. Seperti kata @cnst, mungkin ada alasan mengapa poster asli tidak hanya ingin melakukan rm -f, misalnya mereka mungkin ingin rmvariabel.
Dan Nguyen