Makefile वैरिएबल को कमांड का आउटपुट कैसे असाइन करें


224

मुझे कुछ नियमों को सशर्त रूप से निष्पादित करने की आवश्यकता है, केवल तभी जब पायथन स्थापित किया गया है एक निश्चित संस्करण से अधिक है (कहें 2.5)।

मैंने सोचा था कि मैं ऐसा कुछ कर सकता हूं:

python -c 'import sys; print int(sys.version_info >= (2,5))'

और फिर एक ifeqबयान में आउटपुट ('1' यदि ठीक है, '0' अन्यथा) का उपयोग कर।

एक साधारण बैश शेल स्क्रिप्ट में यह सिर्फ है:

MY_VAR=`python -c 'import sys; print int(sys.version_info >= (2,5))'`

लेकिन वह मेकफाइल में काम नहीं करता है।

कोई सुझाव? मैं इसे प्राप्त करने के लिए किसी अन्य समझदार समाधान का उपयोग कर सकता हूं।


Makefile में मेरे लिए अन्य स्क्रिप्ट्स निष्पादित करने के लिए कमांड वर्क के चारों ओर स्ट्रेंज बैक टिक्स। कुछ और हो सकता है।
लीफ ग्रुएनवॉल्ड्ट

जवाबों:


345

shellजैसे मेक बिलिन का उपयोग करेंMY_VAR=$(shell echo whatever)

me@Zack:~$make
MY_VAR IS whatever

me@Zack:~$ cat Makefile 
MY_VAR := $(shell echo whatever)

all:
    @echo MY_VAR IS $(MY_VAR)

34
शेल एक मानक नहीं है बिल्टइन कमांड बनाओ। यह एक GNU मेक बिलिन है।
डेरेकसन

12
stackoverflow.com/a/2373111/12916 भागने के बारे में एक महत्वपूर्ण नोट जोड़ता है $
जेसी ग्लिक

6
यह सरल उदाहरण काम करता है। यह शेल कमांड पाइपलाइन के साथ भी काम करता है। लेकिन यह जरूरी है कि आप शेल कमांड में $ $ का प्रतिनिधित्व करने के लिए $$ का उपयोग करें
सर्गेई पी। उर्फ ​​अजोर

28
हालांकि सवाल हल्के से पुराना है, यह MY_VAR: = $ (शेल ...) करने के लिए सबसे अच्छा है, अन्यथा हर बार जब MY_VAR का मूल्यांकन किया जाता है, तो यह $ (शेल ...) को फिर से निष्पादित करेगा।
रोस शुल्त्स

मेरे पास शेल और ओपनिंग कोष्ठक के बीच का स्थान था और अंतरिक्ष को हटाने के बाद ही मेरा
मेकफाइल

29

एक में असाइनमेंट लपेटना evalमेरे लिए काम कर रहा है।

# dependency on .PHONY prevents Make from 
# thinking there's `nothing to be done`
set_opts: .PHONY
  $(eval DOCKER_OPTS = -v $(shell mktemp -d -p /scratch):/output)

6
"नोट: यहां @true मेक को सोचने से रोकता है कि कुछ भी नहीं करना है।" उम, यही .PHONY always make these targetsहै के लिए है।
अंडरस्कोर_ड

धन्यवाद! यह मुझे मेकफाइल में "अजीब बैश" को बायपास करने में मदद करता है
नाम जी VU

19

यहाँ नुस्खा के अंदर पाइपिंग और वेरिएबल असाइनमेंट के साथ थोड़ा और अधिक जटिल उदाहरण दिया गया है:

getpodname:
    # Getting pod name
    @eval $$(minikube docker-env) ;\
    $(eval PODNAME=$(shell sh -c "kubectl get pods | grep profile-posts-api | grep Running" | awk '{print $$1}'))
    echo $(PODNAME)

2
मामले में यह कभी भी काम आता है मैं PODNAMEतैनाती के नाम से पाने के लिए थोड़ा समान दृष्टिकोण का उपयोग कर रहा हूं :$(eval PODNAME=$(shell sh -c "kubectl get pod -l app=sqlproxy -o jsonpath='{.items[0].metadata.name}'"))
जनवरी रिक्टर

सिंटैक्स ने मुझे एक दूसरे के लिए तब तक भ्रमित किया जब तक मुझे एहसास नहीं हुआ कि आप शेल शेल एवल (docker-env लाइन पर) और मेक फंक्शन eval (अगली लाइन पर) दोनों का उपयोग कर रहे थे ।
ब्रायन गॉर्डन

17

मैं समस्या को हल करने वाले वास्तविक सिंटैक्स पर दृश्यता बढ़ाने के लिए उत्तर लिख रहा हूं। दुर्भाग्य से, किसी व्यक्ति को तुच्छ के रूप में देखा जा सकता है जो किसी के लिए एक बहुत ही महत्वपूर्ण सिरदर्द बन सकता है, जो एक उचित प्रश्न के सरल उत्तर की तलाश में है।

फ़ाइल को "मेकफाइल" में डालें।

MY_VAR := $(shell python -c 'import sys; print int(sys.version_info >= (2,5))')

all:
    @echo MY_VAR IS $(MY_VAR)

जो व्यवहार आप देखना चाहते हैं, वह निम्नलिखित है (यह मानते हुए कि आपने हाल ही में अजगर स्थापित किया है)।

make
MY_VAR IS 1

यदि आप उपरोक्त पाठ को Makefile में कॉपी और पेस्ट करते हैं, तो क्या आपको यह मिलेगा? शायद ऩही। आपको संभवतः एक त्रुटि मिलेगी जैसे कि यहाँ रिपोर्ट की गई है:

मेकफाइल: 4: *** लापता विभाजक। रुकें

क्यों: क्योंकि यद्यपि मैंने व्यक्तिगत रूप से एक वास्तविक टैब का उपयोग किया है, स्टैक ओवरफ्लो (उपयोगी होने का प्रयास) मेरे टैब को कई स्थानों में परिवर्तित करता है। आप निराश नागरिक नागरिक, अब यह सोचकर नकल करें, कि आपके पास अब वही पाठ है जिसका मैंने उपयोग किया था। मेक कमांड, अब रिक्त स्थान पढ़ता है और पाता है कि "ऑल" कमांड गलत रूप से स्वरूपित है। इसलिए उपरोक्त पाठ को कॉपी करें, पेस्ट करें, और फिर "@echo" से पहले व्हॉट्सएप को एक टैब में बदलें, और यह उदाहरण, अंत में, उम्मीद है, आपके लिए काम करना चाहिए।


निर्भर करता है कि आप किस संपादक में चिपक रहे हैं। मैंने सिर्फ एक ग्रहण मेकफाइल संपादक में कॉपी और पेस्ट किया, और एक प्रमुख टैब (आवश्यकतानुसार) प्राप्त किया।
टेक्नोफाइल

ओह मैंने ऐसा नहीं सोचा था। यहाँ परमाणु।
एलन

11

इस तरह व्यंजनों से सावधान रहें

target:
    MY_ID=$(GENERATE_ID);
    echo $MY_ID;

यह दो काम गलत करता है। नुस्खा में पहली पंक्ति को दूसरी पंक्ति से एक अलग शेल उदाहरण में निष्पादित किया जाता है। इस बीच चर खो जाता है। दूसरी बात गलत है कि $बच नहीं रहा है।

target:
    MY_ID=$(GENERATE_ID); \
    echo $$MY_ID;

दोनों समस्याओं को ठीक कर दिया गया है और परिवर्तनशील है। बैकस्लैश दोनों लाइनों को एक सिंगल शेल में चलाने के लिए जोड़ती है, इसलिए वेरिएबल की सेटिंग और वेरिएबल आफ्टरवर्ड की रीडिंग काम करती है।

मुझे लगता है कि मूल पोस्ट ने कहा कि शेल कमांड के परिणाम को MAKE वेरिएबल में कैसे लाया जाता है, और यह उत्तर दिखाता है कि इसे शेल वेरिएबल में कैसे लाया जाए। लेकिन अन्य पाठकों को फायदा हो सकता है।

एक अंतिम सुधार, अगर उपभोक्ता एक "पर्यावरण चर" सेट होने की उम्मीद करता है, तो आपको इसे निर्यात करना होगा।

my_shell_script
    echo $MY_ID

मेकफाइल में इसकी आवश्यकता होगी

target:
    export MY_ID=$(GENERATE_ID); \
    ./my_shell_script;

आशा है कि किसी की मदद करता है। सामान्य तौर पर, किसी को भी व्यंजनों के बाहर किसी भी वास्तविक कार्य को करने से बचना चाहिए, क्योंकि यदि कोई d -dry-run ’विकल्प के साथ मेकफाइल का उपयोग करता है, तो केवल यह देखने के लिए कि वह क्या करेगा, इसका कोई अवांछनीय दुष्प्रभाव नहीं होगा। प्रत्येक $(shell)कॉल का संकलन समय पर मूल्यांकन किया जाता है और कुछ वास्तविक कार्य गलती से हो सकते हैं। वास्तविक कार्य को छोड़ने के लिए बेहतर है, जैसे आईडी बनाना, व्यंजनों के अंदर जब संभव हो।


9

जीएनयू मेक के साथ, आप उपयोग कर सकते हैं shellऔर evalमनमाने ढंग से कमांड लाइन आमंत्रण से दुकान, रन और असाइन उत्पादन के लिए। नीचे दिए गए उदाहरण और वे जो उपयोग के बीच का अंतर :=है :=काम होता है एक बार (जब यह का सामना करना पड़ा है) और सभी के लिए। पुनरावर्ती विस्तारित चर के साथ सेट =थोड़ा अधिक "आलसी" हैं; अन्य चर के संदर्भ तब तक बने रहते हैं जब तक कि चर को संदर्भित नहीं किया जाता है, और बाद के पुनरावर्ती विस्तार में प्रत्येक बार चर को संदर्भित किया जाता है, जो "सुसंगत, कॉल करने योग्य, स्निपेट्स" बनाने के लिए वांछनीय है। अधिक जानकारी के लिए चर सेट करने पर मैनुअल देखें ।

# Generate a random number.
# This is not run initially.
GENERATE_ID = $(shell od -vAn -N2 -tu2 < /dev/urandom)

# Generate a random number, and assign it to MY_ID
# This is not run initially.
SET_ID = $(eval MY_ID=$(GENERATE_ID))

# You can use .PHONY to tell make that we aren't building a target output file
.PHONY: mytarget
mytarget:
# This is empty when we begin
    @echo $(MY_ID)
# This recursively expands SET_ID, which calls the shell command and sets MY_ID
    $(SET_ID)
# This will now be a random number
    @echo $(MY_ID)
# Recursively expand SET_ID again, which calls the shell command (again) and sets MY_ID (again)
    $(SET_ID)
# This will now be a different random number
    @echo $(MY_ID)

आपके पास पहली अच्छी व्याख्या है जो मैंने हर बार की है। धन्यवाद। हालांकि जोड़ने वाली एक बात यह है कि अगर $(SET_ID)एक ifखंड के अंदर रहता है जो कि झूठा है तो इसे अभी भी कहा जाता है
रोमन

यह अभी भी कहा जाता है क्योंकि अगर stmts का मूल्यांकन मेकाइल कंपाइल-टाइम पर रन-टाइम में नहीं किया जाता है। रन-टाइम विशिष्ट निर्देशों के लिए, उन्हें व्यंजनों में डालें। यदि वे सशर्त हैं, तो नुस्खा के हिस्से के रूप में, अगर stmts, बैश / शेल में लिखा गया है, तो जोड़ें।
जुराज

0

नीचे दिए गए उदाहरण में, मैंने Makefile फ़ोल्डर पथ को संग्रहीत किया है LOCAL_PKG_DIRऔर फिर LOCAL_PKG_DIRलक्ष्य में चर का उपयोग किया है।

makefile:

LOCAL_PKG_DIR := $(shell eval pwd)

.PHONY: print
print:
    @echo $(LOCAL_PKG_DIR)

टर्मिनल आउटपुट:

$ make print
/home/amrit/folder
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.