अगर मेकफाइल में फ़ाइल मौजूद है तो मैं कैसे जांच कर सकता हूं ताकि मैं इसे हटा सकूं?


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 एक चर या एक वास्तविक फ़ाइल नाम है?
बगफाइंडर

myApp myApplication यानी बिल्ड प्रक्रिया द्वारा फ़ाइल नाम के लिए है।
Abruzzo Forte e Gentile

5
यदि आप बस रोकना चाहते हैं यदि फ़ाइल मौजूद नहीं है, तो rm -rf myAppविकल्प हो सकता है। या -rm myApprm से त्रुटि को अनदेखा करने के लिए डैश ( ) के साथ कमांड को पूर्ववर्ती करें (यह हालांकि एक बदसूरत संदेश प्रिंट करेगा)।
thomasa88

1
आपकी समस्या यह थी कि एक नियम में प्रत्येक पंक्ति को एक अलग कमांड के रूप में मानते हैं और उन्हें व्यक्तिगत रूप से शेल में भेजते हैं। यह अपने आप ही 'अगर -a myApp]' चलाने जैसा है। यदि आपको यह त्रुटि मिलती है, तो आपको या तो एक समाधान की आवश्यकता होती है, जो लाइनों को एक (उपयोग) में शामिल करता है या जो प्रत्येक पंक्ति से दूसरे के साथ समाप्त होता है। अब इनमें से कई नीचे हैं।
माइकल

जवाबों:


40

दूसरे शीर्ष उत्तर में उल्लेख किया गया है 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

तब तक काम नहीं किया जब तक कि मैं
Tar

3
यह उत्तर थोड़ा अजीब होगा; फ़ाइल की जाँच तब होती है जब मेकफ़ाइल संसाधित होता है लेकिन कार्रवाई बाद में होगी जब लक्ष्य द्वारा निर्मित किया जाता है। यदि आप इस बीच फ़ाइल को हटाते हैं तो फ़ाइल नहीं बनाई जाएगी। मैंने इसे स्पष्ट करने के लिए एक संपादन में रखा है।
माइकल

बहुत धन्यवाद! यह बिंदु मैनुअल पढ़ने से स्पष्ट नहीं था।
केविन बुक्स

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

1
वाइल्डकार्ड का शानदार उपयोग, इसलिए इसे मेकफाइल के साथ ही किया जा सकता है। नीट :)
अनूप

3
यह समझने में भी मदद करता है कि $(wildcard pattern)वास्तव में क्या करता है। लिंक देखें
डॉ। दान

1
अधिक संक्षिप्त:FILE_EXISTS := $(or $(and $(wildcard $(PATH_TO_FILE)),1),0)
cmaster -

2
यह ध्यान देने योग्य है कि यदि आप साइबरविन के तहत विंडोज पर चल रहे हैं, तो वाइल्डकार्ड का इस तरह से उपयोग करना फ़ाइल नाम पर केस सेंसिटिव मैच करता है, इसलिए यदि फाइल मौजूद है, लेकिन पथ से भिन्न मामले के साथ यह नहीं मिलेगा। मेकफाइल के भीतर इस व्यवहार को ओवरराइड करने का कोई तरीका प्रतीत नहीं होता है।
रोजर सैंडर्स

59

समस्या यह है कि जब आप अपनी कमांड को कई लाइनों में विभाजित करते हैं। तो, आप या तो \ऊपर के रूप में निरंतरता के लिए लाइनों के अंत में उपयोग कर सकते हैं या आप &&ऑपरेटर के साथ एक पंक्ति में सब कुछ प्राप्त कर सकते हैं ।

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
अंडरस्कोर_ड

सलाह के लिये धन्यवाद। -fडिफ़ॉल्ट रूप से परिवर्तित , क्योंकि इसका उपयोग करना अधिक सामान्य है।
22

मैं testविंडोज पर कैसे प्राप्त कर सकता हूं ?
थोवा

3
आदेश में यह काम करने के लिए आपको || trueअंत में जोड़ने की आवश्यकता है ताकि फ़ाइल वापस मौजूद न होने पर कमांड वापस आ जाए।
ज्यूबिक

2
@AndrewMackenzie test -f myApp || CMD, नोटिस ||, तो अगर -fअसफल हो जाएगा - मौजूद नहीं है ( ||), तो कमांड चलाएं। क्या इस का कोई मतलब निकलता है?
कीनॉर्ब

50

इसे निरंतरता के लिए लाइन के अंत में एक बैकस्लैश की आवश्यकता हो सकती है (हालांकि शायद यह मेक के संस्करण पर निर्भर करता है):

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

2
एक Makefile वाक्यविन्यास नहीं लगता है? sunsite.ualberta.ca/Documentation/Gnu/make-3.79/html_chapter/…
होम्स

@ इसकी बैश सिंटेक्स है। नई लाइनों से बचकर यह इसे एक बैश कमांड के रूप में नियंत्रित करने की अनुमति देता है। makeनई लाइन में डिफ़ॉल्ट रूप से एक नया बैश कमांड होगा। इसके प्रमुख कैवेट, \ लाइनों के अंत में बहुत सारे होने की झुंझलाहट के अलावा यह है कि हर आदेश को समाप्त कर दिया जाना चाहिए, ;जो अन्यथा बैश में निहित होगा।
फ्लुंगो

1
सही उत्तर @holms द्वारा है। इस प्रयोजन के लिए न तो '\' और न ही वाइल्डकार्ड बिल्कुल उपयुक्त है। आप वाइल्डकार्ड का उपयोग क्यों करेंगे इसका कारण कोड स्पष्टता है। न केवल यह विधि कम पठनीय है, यह सिंटैक्स त्रुटियों के लिए अधिक प्रवण है।
मैत्रेय

1
लिंक @holms अब और काम नहीं करता है, इसके बजाय gnu.org/software/make/manual/make.html#Conditionals का उपयोग करें
fero

यह एक शानदार उत्तर है क्योंकि यह मेल खाता है कि मूल प्रश्नकर्ता ने क्या गलत किया है और यह इस बात पर निर्भर करता है कि जिस समय मेकफाइल शुरू किया गया था उस समय के बजाय लक्ष्य के निर्माण के समय फाइल मौजूद है या नहीं, जो कि ज्यादातर लोगों से अपेक्षा करेगा और अधिकांश समय चाहते हैं। कुछ अजीब मामलों में @cnst से जवाब बेहतर होगा।
माइकल

31

या बस एक लाइन पर रखें, जैसा makeकि यह पसंद है:

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

कि इस मामले में एक महान जवाब है (और upvotes मिलना चाहिए), लेकिन इतनी अच्छी तरह से करता है, तो कार्रवाई और अधिक जटिल थे काम नहीं करेगा, जिस स्थिति में सिर्फ उपयोग भी कर \
माइकल

[-a myApp] && rm myApp
रॉबिन

14

एक अर्धविराम याद आ रहा है

if [ -a myApp ];
then
  rm myApp
fi

हालाँकि, मुझे लगता है कि आप त्रुटि संदेश को रोकने के लिए हटाने से पहले अस्तित्व की जाँच कर रहे हैं। यदि ऐसा है, तो आप केवल rm -f myApp"बलों" को हटाने का उपयोग कर सकते हैं , अर्थात यदि फ़ाइल मौजूद नहीं थी तो त्रुटि नहीं है।


1
थाहट वही है जो मैं करना चाहता था। बहुत बहुत धन्यवाद।
Abruzzo Forte e Gentile

1
यह एक मेकफाइल में काम नहीं करेगा क्योंकि अगर अभी भी कई लाइनों में फैला हुआ है - तो आपको इसे एक लाइन पर रखना होगा या \ es का उपयोग करना होगा। और यहां तक ​​कि अगर आपने \ es को जोड़ा तो आप अभी भी कुछ अर्ध-कॉलोनों को याद नहीं कर रहे हैं।
माइकल 16

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.

इससे मुझे मदद मिली, मुझे लगता है कि कुछ लोग चूक गए थे कि ओपी मेकअप के बारे में पूछ रहा था। मुझे समझ नहीं आया कि "&& गूंज -n हां" क्यों आवश्यक है। स्पष्टीकरण: यदि परीक्षण -ई रिटर्न 1 (नहीं मिला) तो शेल इको कमांड को निष्पादित नहीं करेगा, और इसलिए ifeq में हां से मेल नहीं खाएगा
ब्रैड ड्रे

मुझे लगता है कि आप अपने स्पष्टीकरण विवरण में इसे सही ढंग से समझते हैं।
रॉबिन ह्सु

@ ब्रैडरे - एनएल के बिना स्ट्रिंग में echo -n yesसफलता बदल testजाती है yesifeqतो कठिन कोडित के साथ तुलना कर सकते हैं yes। सभी क्योंकि ifeqस्ट्रिंग की तुलना करना चाहते हैं, शेल कमांड से सफलता की स्थिति नहीं।
जेसी चिशोल्म

8

एक पंक्ति समाधान:

   [ -f ./myfile ] && echo exists

त्रुटि कार्रवाई के साथ एक पंक्ति समाधान:

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

मेरे make cleanनिर्देशों में प्रयुक्त उदाहरण :

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

और make cleanहमेशा बिना किसी त्रुटि संदेश के काम करता है!


3
सिर्फ @rm -f myfile करते हैं। "-F" ध्वज के कारण, "rm" 0 के साथ बाहर निकलेगा, भले ही फ़ाइल मौजूद हो या न हो।
एलेक्सी पोलोनस्की

या, -rm myfileलीड डैश बता रहा है कि किसी भी त्रुटि को अनदेखा करें।
जेसी चिशोल्म

1
मेरे मामले में, छोड़ कर || <त्रुटि कार्रवाई> समस्याओं का कारण बना। आपका अंतिम उदाहरण, जहां आप सही थे यदि फ़ाइल मौजूद नहीं थी, तो इसे अच्छी तरह से संबोधित किया। धन्यवाद!
Flic

मेरे लिए मायफाइल के लिए रास्ता एपोस्ट्रोफ (') के साथ होना चाहिए:@[ -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/'

इस त्रुटि के होने के बाद, मुझे पता है कि कैसे चेक करना है कि क्या कोई फ़ाइल मौजूद है, और यह उत्तर है ...


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

लाइनों को जारी रखने के लिए और उपयोग करके @ मार्क-विल्किंस से एक जैसे उत्तर; उन्हें शेल में समाप्त करने के लिए या @kenorb के लोगों की तरह इसे एक पंक्ति में बदलना अच्छा है और इस समस्या को ठीक कर देगा।

मूल समस्या का एक सरल उत्तर है (जैसा कि @ alexey-polonsky ने बताया है)। Rm -f ध्वज का उपयोग करें ताकि यह एक त्रुटि को ट्रिगर न करे

rm -f myApp

यह सरल, तेज और अधिक विश्वसनीय है। बस एक स्लैश और एक खाली चर के साथ समाप्त न होने के लिए सावधान रहें

rm -f / $ (myAppPath) # यह कभी भी करें

आप अपने सिस्टम को समाप्त कर सकते हैं।


1
ओपी के पास जो फ़ाइल है, उसे हटाने के लिए यह एक अच्छा उत्तर है, लेकिन मुझे पूरा यकीन है कि ज्यादातर लोग जो इस सवाल को ढूंढते हैं, वे वास्तव में आपकी फ़ाइलों को हटाने की तलाश में नहीं हैं; यह वास्तव में इस तथ्य से स्पष्ट होता है कि अधिकांश उत्तर बिल्कुल भी उल्लेख नहीं करते हैं rm; BTW, मुझे पूरा यकीन है कि rm -f /$(myAppPath)कोई भी नुकसान नहीं होगा, क्योंकि /, एक निर्देशिका है, और -rगायब है।
cnst

यह एक सरल उपाय नहीं है। जैसे @cnst ने कहा, ऐसे कारण हो सकते हैं कि मूल पोस्टर केवल एक करना नहीं चाहता है rm -f, जैसे वे rmएक चर के लिए चाहते हो सकते हैं ।
डैन गुयेन
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.