मैं सशर्त रूप से 'समय' के माध्यम से एक उपधारा कैसे पारित कर सकता हूं?


9

मेरे पास वैग्रांट बॉक्स के लिए एक सेटअप स्क्रिप्ट है जहां मैं एकल चरणों को मापता था time। अब मैं समय माप को सशर्त रूप से सक्षम या अक्षम करना चाहूंगा।

उदाहरण के लिए, पहले एक लाइन की तरह दिखेगा:

time (apt-get update > /tmp/last.log 2>&1)

अब मुझे लगा कि मैं बस कुछ ऐसा कर सकता हूं:

MEASURE_TIME=true
[[ $MEASURE_TIME = true ]] && TIME="time --format=%e" || TIME=""

$TIME (apt-get update > /tmp/last.log 2>&1)

लेकिन यह काम नहीं करेगा:

syntax error near unexpected token `apt-get'
`$TIME (apt-get update > /tmp/last.log 2>&1)'

यहाँ क्या समस्या है?


3
फ्लक्स कैपेसिटर के काम करने के लिए आपको बस लक्ष्य वेग तक पहुँचने की आवश्यकता है ;)
गोल्डिलॉक्स

2
@goldilocks आप चुंबक का मतलब है ? ;)
एक CVn

जवाबों:


13

एक सब- टाइम के लिए सक्षम होने के लिए , आपको time कीवर्ड की आवश्यकता है , कमांड की नहीं।

timeकीवर्ड, भाषा का हिस्सा है, केवल जब सचमुच में प्रवेश किया इस तरह के रूप में पहचाना जाता है और एक आदेश का पहला शब्द के रूप में (और के मामले में ksh93, फिर अगले टोकन एक साथ शुरू नहीं करता है -)। यहां तक ​​कि प्रवेश "time"करना अकेले काम नहीं करेगा $TIME(और timeइसके बजाय कॉल के रूप में लिया जाएगा )।

आप यहां उपनामों का उपयोग कर सकते हैं जो कि दूसरे दौर के पार्सिंग प्रदर्शन से पहले विस्तारित होते हैं (ताकि शेल उस timeकीवर्ड को पहचान सके ):

shopt -s expand_aliases
alias time_or_not=
TIMEFORMAT=%E

MEASURE_TIME=true
[[ $MEASURE_TIME = true ]] && alias time_or_not=time

time_or_not (apt-get update > /tmp/last.log 2>&1)

time कीवर्ड विकल्प (के लिए छोड़कर नहीं ले करता है -pमें bash), लेकिन प्रारूप के साथ सेट किया जा सकता TIMEFORMATमें चर bash। (यह shoptहिस्सा भी बहुत महत्वपूर्ण है bash, अन्य गोले आमतौर पर उस की जरूरत नहीं है)।


आपने कहा "एक सब-टाइम के लिए सक्षम होने के लिए, आपको समय कीवर्ड की आवश्यकता है"। मुझे आश्चर्य है कि इस व्यवहार ने कुछ दस्तावेज कहां हैं?
congonglm

@cuonglm, देखेंinfo -f bash --index-search=time
स्टीफन चेज़लस

3

हालांकि aliasयह करने का एक तरीका है, यह भी किया जा सकता है eval- यह सिर्फ इतना है कि आप evalकमांड के निष्पादन के लिए इतना नहीं चाहते हैं जितना आप evalकमांड की घोषणा करना चाहते हैं ।

मुझे aliasतों पसंद है - मैं हर समय उनका उपयोग करता हूं, लेकिन मुझे फ़ंक्शन बेहतर हैं - विशेष रूप से मापदंडों को संभालने की उनकी क्षमता और उन्हें कमांड स्थिति में विस्तारित करने की आवश्यकता नहीं है जैसा कि aliases के लिए आवश्यक है ।

तो मैंने सोचा कि शायद आप भी यही कोशिश करना चाहेंगे:

_time() if   set -- "${IFS+IFS=\$2;}" "$IFS" "$@" && IFS='
';      then set -- "$1" "$2" "$*"; unset IFS
             eval "$1 $TIME ${3#"$1"?"$2"?}"
        fi

$IFSबिट मुख्य रूप से के बारे में है $*। यह महत्वपूर्ण है कि है ( subshell bit )है भी एक खोल विस्तार का परिणाम है और इसलिए है ताकि एक parsable स्ट्रिंग मैं उपयोग में तर्क का विस्तार करने में "$*" (नहीं है eval "$@", वैसे, जब तक आप आर्ग की कर रहे हैं निश्चित सभी रिक्त स्थान पर शामिल हो सकते हैं) । आर्गन्स के बीच विभाजन परिसीमन "$*"पहले बाइट में है $IFS, और इसलिए यह निश्चित है कि इसका मूल्य बनाए बिना आगे बढ़ना खतरनाक हो सकता है। तो समारोह की बचत होती है $IFS, एक करने के लिए यह सेट \nकाफी लंबे समय के लिए ewline set ... "$*"में "$3", unsetयह है, तो अपने मूल्य को रीसेट करता है अगर यह पहले से एक था।

यहाँ थोड़ा डेमो है:

TIME='set -x; time'
_time \( 'echo "$(echo any number of subshells)"' \
         'command -V time'                        \
         'hash time'                              \
      \) 'set +x'

आप देखते हैं कि मैंने दो कमांड $TIMEवहाँ रखे हैं - कोई भी संख्या ठीक है - यहां तक ​​कि कोई भी नहीं - लेकिन सुनिश्चित करें कि यह बच गया है और ठीक से उद्धृत किया गया है - और उसी के तर्क के लिए जाता है _time()। जब उन्हें मार दिया जाएगा, तो वे सभी एक ही कमांड स्ट्रिंग में \nसमाहित हो जाएंगे - लेकिन प्रत्येक arg की अपनी स्वयं की ईलाइन होती है और इसलिए वे अपेक्षाकृत आसानी से फैल सकते हैं। या फिर आप उन सभी को एक में \nलपका सकते हैं, यदि आप चाहें, और उन्हें इविलाइज़ या सेमी-कॉलन या व्हाट्स-हैव-यू पर अलग कर सकते हैं। बस यह सुनिश्चित करें कि एक एकल तर्क एक कमांड का प्रतिनिधित्व करता है जिसे आप कॉल करते समय स्क्रिप्ट में अपनी लाइन में डालने में सहज महसूस करेंगे। \(, उदाहरण के लिए, ठीक है, तो जब तक यह अंततः साथ है \)। मूल रूप से सामान्य सामान।

जब evalउपरोक्त स्निपेट खिलाया जाता है तो ऐसा लगता है:

+ eval 'IFS=$2;set -x; time (
echo "$(echo any number of subshells)"
command -V time
hash time
)
set +x'

और, इसके परिणाम दिखते हैं ...

आउटपुट

+++ echo any number of subshells
++ echo 'any number of subshells'
any number of subshells
++ command -V time
time is a shell keyword
++ hash time
bash: hash: time: not found

real    0m0.003s
user    0m0.000s
sys     0m0.000s
++ set +x

hashत्रुटि को इंगित करता है कि मैं एक की जरूरत नहीं है /usr/bin/timeस्थापित (क्योंकि मैं नहीं) और commandहमें पता है जो समय चल रहा है। अनुगामी set +xएक और कमांड है जिसे बाद में निष्पादित time किया जाता है (जो संभव है) - evalकुछ भी होने पर इनपुट कमांड के साथ सावधान रहना महत्वपूर्ण है ।


इसे न बनाने का कोई कारण _time() { eval "$TIME $@"; }? किसी फ़ंक्शन का उपयोग करने से चर के लिए एक अलग गुंजाइश पेश करने का दोष है (
उपधारा के

@ StéphaneChazelas - "$@"विस्तार में उद्धरण के कारण । मुझे एक ही arg पसंद है eval- यह अन्यथा डरावना है। उम्म्म .... आप अलग-अलग दायरे के बारे में कैसे सोचते हैं? मैंने सोचा था कि यह सिर्फ functionकार्य था ...
mikeserv

evalनिष्पादित करने से पहले इसके आर्गनों में शामिल होता है जो कि आप बहुत जटिल तरीके से करने की कोशिश कर रहे हैं। मेरा मतलब था कि _time 'local var=1; blah'उस varस्थानीय को वह बना देगा _time, या वह उस फ़ंक्शन का _time 'echo "$#"'प्रिंट लेगा , न कि कॉल करने वाले का। $#_time
स्टीफन चेज़लस

@ स्टीफनचेलजैस - मुझे यहां आपके लिए दो टैब पूरे हुए। सही - evalरिक्त स्थान पर अपने आर्गन्स को समेटता है - जो कि जैसा आप कहते हैं, ठीक वैसा ही मैं यहां करता हूं - हालांकि यह जन्मजात इरादा नहीं था। मैं ठीक करने जा रहा हूँ। evalआईएनजी "$*"विरोध के रूप में "$@"एक आदत है जिसे मैंने कई रन-इन के बाद उठाया था command not foundजब गलत जगह पर आर्ग्स जुड़ गए थे। किसी भी मामले में, हालांकि फ़ंक्शन में अंततः आर्ग को निष्पादित किया जाता है, लेकिन यह सरल है कि उन्हें मंगलाचरण में विस्तारित किया जाए, मुझे लगता है। यह वही है जो मैं "$#"वैसे भी करूंगा ।
मोकेसर

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