एक स्क्रिप्ट के निष्पादन समय को प्रभावी ढंग से कैसे प्राप्त करें?


339

मैं एक स्क्रिप्ट के पूरा होने का समय प्रदर्शित करना चाहूंगा।

वर्तमान में मैं क्या कर रहा हूँ -

#!/bin/bash
date  ## echo the date at start
# the script contents
date  ## echo the date at end

यह सिर्फ स्क्रिप्ट की शुरुआत और अंत का समय है। क्या प्रोसेसर समय / io समय, आदि की तरह एक अच्छा दानेदार उत्पादन प्रदर्शित करना संभव होगा?



मुझे लगता है कि अस्थायी स्वीकारोक्ति के कारण वर्तमान स्वीकृत उत्तर वास्तव में पर्याप्त नहीं है।
लेओ लेपोल्ड हर्ट्ज़ '

1
@CiroSantilli 烏坎 iro 2016 事件 ill proposed मुझे लगता है कि आपके प्रस्तावित धागे अभी भी लौकिक घटनाओं के प्रभाव को खत्म करने के लिए पर्याप्त नहीं है।
लेओ लेपोल्ड हर्ट्ज़ '

इसके अलावा संबंधित: stackoverflow.com/questions/5152858/… या कुछ हद तक unix.stackexchange.com/questions/334145/…
phk

एक कमांड है जिसे आप चला सकते हैं और फिर कई बार सभी यूनिक्स कमांड अपने आप हो जाते हैं, कैसे भूल गए?
पाउडर 366 16

जवाबों:


448

timeजब आप स्क्रिप्ट को कॉल करते हैं तो बस उपयोग करें:

time yourscript.sh

61
यह तीन बार आउटपुट: real, userऔर sys। इनके अर्थ के लिए, यहाँ देखें ।
गैरेट

27
और "वास्तविक" शायद वही है जो लोग जानना चाहते हैं - "रियल दीवार घड़ी का समय है - कॉल की समाप्ति से शुरू होने तक का समय"
ब्रैड पार्क्स

3
वहाँ एक फ़ाइल में stdout पर कब्जा करने का एक तरीका है? उदाहरण के लिए, कुछ इस तरहtime $( ... ) >> out.txt
जॉन

1
आप कमांड लाइन पर कमांड के अनुक्रमों के लिए भी ऐसा कर सकते हैं, जैसे:time (command1 && command2)
मीटार

1
या, वह अपनी स्क्रिप्ट में, बस कर सकता है: गूंज $ SECONDS यह मानते हुए बैश है ....
Crossfit_and_Beer

169

यदि timeकोई विकल्प नहीं है,

start=`date +%s`
stuff
end=`date +%s`

runtime=$((end-start))

30
ध्यान दें कि यह केवल तभी काम करता है जब आपको उप-सेकंड सटीक की आवश्यकता न हो। कुछ उपयोगों के लिए जो स्वीकार्य हो सकते हैं, दूसरों के लिए नहीं। थोड़ी बेहतर सटीकता के लिए (आप अभी भी dateदो बार आह्वान कर रहे हैं , उदाहरण के लिए, इसलिए आप व्यवहार में मिलिसकॉन्ड सटीक को सर्वोत्तम रूप से प्राप्त कर सकते हैं , और शायद कम), उपयोग करने का प्रयास करें date +%s.%N। ( %Nपूरे सेकंड के बाद से नैनोसेकंड है।)
एक 19:17

अच्छी बात। मैंने कीबोर्ड छोड़ने के बाद ही सोचा था लेकिन वापस नहीं आया। ^ ^ यह भी याद रखें, ओपी, कि "तारीख" खुद को चलाने के समय में कुछ मिलीसेकंड जोड़ देगा।
रोब बॉश

2
@ क्रिस ओ। इसे इंगित करना अच्छा है; बैश अंकगणितीय विस्तार पूर्णांक-मात्र है। मुझे दो स्पष्ट विकल्प दिखाई देते हैं; या तो दिनांक प्रारूप स्ट्रिंग में अवधि खोदो (और युग के बाद से नैनो के रूप में परिणामी मूल्य का इलाज करें), इसलिए उपयोग करें date +%s%N, या कुछ अधिक सक्षम का उपयोग करें bcजैसे jwchew जैसे दो मूल्यों से वास्तविक रनटाइम की गणना करना। फिर भी, मुझे लगता है कि यह दृष्टिकोण इसे करने का एक उप-तरीका है; timeयदि उपर्युक्त कारणों से उपलब्ध हो तो बेहतर है।
बजे एक CVn

10
बस स्थापित करें bcऔर फिर ऐसा करें:runtime=$( echo "$end - $start" | bc -l )
redolent

10
यदि आपकी स्क्रिप्ट में कई मिनट लगते हैं, तो उपयोग करें:echo "Duration: $((($(date +%s)-$start)/60)) minutes
rubo77

75

बस timesअपनी स्क्रिप्ट से बाहर निकलने पर तर्क के बिना कॉल करें ।

के साथ kshया इसके बजाय zsh, आप भी उपयोग कर सकते हैं time। के साथ zsh, timeआपको उपयोगकर्ता और सिस्टम CPU समय के अलावा दीवार घड़ी का समय भी देगा ।

अपनी स्क्रिप्ट की निकास स्थिति को संरक्षित करने के लिए, आप इसे बना सकते हैं:

ret=$?; times; exit "$ret"

या आप पर एक जाल भी जोड़ सकते हैं EXIT:

trap times EXIT

जब भी शेल बाहर निकलता है और बाहर निकलने की स्थिति को संरक्षित किया जाएगा, उस समय को कहा जाएगा।

$ bash -c 'trap times EXIT; : {1..1000000}'
0m0.932s 0m0.028s
0m0.000s 0m0.000s
$ zsh -c 'trap time EXIT; : {1..1000000}'
shell  0.67s user 0.01s system 100% cpu 0.677 total
children  0.00s user 0.00s system 0% cpu 0.677 total

यह भी ध्यान दें कि सभी में bash, kshऔर zshएक $SECONDSविशेष चर है जो स्वचालित रूप से हर सेकंड बढ़ जाता है। दोनों में zshऔर ksh93, उस चर typeset -F SECONDSको और अधिक सटीकता प्राप्त करने के लिए फ्लोटिंग पॉइंट (के साथ ) भी बनाया जा सकता है । यह केवल दीवार घड़ी का समय है, CPU समय नहीं है।


12
वह $ SECONDS चर बहुत उपयोगी है, धन्यवाद!
andbuckley

क्या आपका दृष्टिकोण लौकिक घटनाओं के प्रभाव को समाप्त करता है? - - मुझे लगता है कि आपका दृष्टिकोण timeपहले प्रस्तुत दृष्टिकोण के निकट है । - - मुझे लगता है कि timeitMATLAB कोड में प्रस्तुत दृष्टिकोण यहां उपयोगी हो सकता है।
लेओ लेपोल्ड हर्ट्ज़ '

2
हाय, @ स्टीफन चेज़लस। मैंने पाया timesकि दीवार समय नहीं दे रही है, है ना? उदाहरण के लिए,bash -c 'trap times EXIT;sleep 2'
user15964


32

बैंडबाजे के लिए मुझे थोड़ी देर हो गई है, लेकिन मेरे समाधान को पोस्ट करने के लिए (उप-दूसरी परिशुद्धता के लिए) पोस्ट करना चाहता था, अगर दूसरे को खोज के माध्यम से इस थ्रेड पर ठोकर लगती है। आउटपुट दिनों, घंटों, मिनटों और अंत में सेकंड के प्रारूप में है:

res1=$(date +%s.%N)

# do stuff in here

res2=$(date +%s.%N)
dt=$(echo "$res2 - $res1" | bc)
dd=$(echo "$dt/86400" | bc)
dt2=$(echo "$dt-86400*$dd" | bc)
dh=$(echo "$dt2/3600" | bc)
dt3=$(echo "$dt2-3600*$dh" | bc)
dm=$(echo "$dt3/60" | bc)
ds=$(echo "$dt3-60*$dm" | bc)

printf "Total runtime: %d:%02d:%02d:%02.4f\n" $dd $dh $dm $ds

आशा है कि किसी को यह उपयोगी लगता है!


1
मुझे लगता है कि गणना करने के लिए 'bc' का उपयोग करने के अलावा कोई और (केवल bash) तरीका नहीं है। BTW वास्तव में अच्छी स्क्रिप्ट;)
tvl

1
सावधान रहें कि FreeBSD dateउप-सेकंड की सटीकता का समर्थन नहीं करता है और Nटाइमस्टैम्प के लिए " शाब्दिक" को जोड़ देगा ।
एंटोन सैमसोनोव

1
बहुत अच्छी स्क्रिप्ट है, लेकिन मेरे बैश सबसॉन्ड के हिस्से को नहीं संभालते। मैंने यह भी सीखा, कि / bc में 1 प्रभावी रूप से स्ट्रिप्स है, इसलिए मैंने $ ds की गणना में @ / 1 @ जोड़ा, और यह अब बहुत अच्छा दिखाता है!
डैनियल

1
bc modulo का समर्थन करता है dt2=$(echo "$dt%86400" | bc):। बस कह रहा हूं ... बीटीडब्ल्यू मैं फॉर्म को पसंद करता हूं dt2=$(bc <<< "${dt}%86400")लेकिन यह पूरी तरह से व्यक्तिगत है।
दानी_ D

16

इसके लिए मेरी विधि bash:

# Reset BASH time counter
SECONDS=0
    # 
    # do stuff
    # 
ELAPSED="Elapsed: $(($SECONDS / 3600))hrs $((($SECONDS / 60) % 60))min $(($SECONDS % 60))sec"

यह बीता हुआ समय दिखाता है, लेकिन यह प्रश्न में अनुरोध के अनुसार, "प्रोसेसर समय, I / O समय की तरह अच्छा दानेदार आउटपुट" नहीं दिखाता है।
रोमीमा

3
प्रश्न के उत्तर के लिए खोज करने वालों को इस समाधान के उपयोगी होने की संभावना है। आपकी टिप्पणी ओपी प्रश्न के लिए बेहतर होगी।
मार्क

5
#!/bin/bash
start=$(date +%s.%N)

# HERE BE CODE

end=$(date +%s.%N)    
runtime=$(python -c "print(${end} - ${start})")

echo "Runtime was $runtime"

हां, यह पायथन को बुलाता है, लेकिन अगर आप इसके साथ रह सकते हैं तो यह काफी अच्छा है।


5
उस pythonकमांड को एक सबशेल में चलाने और इसके आउटपुट को पढ़ने से सावधान रहें, अधिकांश मौजूदा सिस्टम पर कई लाखों नैनोसेकंड ले जाएंगे। दौड़ने के लिए भी date
स्टीफन चेज़लस

7
"कई लाख नैनोसेकंड" कई मिलीसेकंड है। स्क्रिप्ट्स को टाइम करने वाले लोग आमतौर पर इसके बारे में बहुत चिंतित नहीं होते हैं (जब तक कि वे प्रति मेगासेकंड की कई बिलियन स्क्रिप्ट नहीं चलाते हैं)।
जिल्क

2
यह भी देखें कि, भले ही गणना एक अजगर प्रक्रिया के अंदर की जाती है, लेकिन अजगर को लागू करने से पहले मूल्यों को पूरी तरह से एकत्र किया गया था। स्क्रिप्ट के निष्पादन का समय "लाखों नैनोसेकंड" ओवरहेड के बिना, सही ढंग से मापा जाएगा।
विक्टर श्रोडर

5

यह प्रश्न काफी पुराना है, लेकिन इसे करने का मेरा पसंदीदा तरीका खोजने की कोशिश में यह धागा बहुत ऊपर आया ... और मुझे आश्चर्य है कि किसी ने भी इसका उल्लेख नहीं किया:

perf stat -r 10 -B sleep 1

'perf' एक प्रदर्शन का विश्लेषण करने वाला उपकरण है, जो कर्नेल में 'टूल्स / perf' के तहत शामिल होता है और अक्सर CentOS में एक अलग पैकेज ('perf' के रूप में और Debian / Ubuntu पर 'linux-tools') के रूप में स्थापित करने के लिए उपलब्ध होता है। लिनक्स कर्नेल परफेक्ट विकी के बारे में अधिक जानकारी है।

रनिंग 'परफैक्ट स्टेट' अंत में औसत निष्पादन समय सहित काफी विवरण देता है:

1.002248382 seconds time elapsed                   ( +-  0.01% )

2
क्या है perf?
बी लेयर

@ बी लेयर - ने 'पूर्ण' का संक्षिप्त विवरण देने के लिए मेरे उत्तर को संपादित किया।
जाहिद

1
perf statअब शिकायत करता है कि "आपके पास आँकड़े एकत्र करने की अनुमति नहीं हो सकती है।" जब तक आप कुछ कमांड नहीं चलाते हैं sudo, जो सभी परिदृश्यों में बेकार हो जाता है, जहां आप पूरी तरह से लक्ष्य मशीन के मालिक नहीं हैं।
आलमार

4

एक छोटा शेल फ़ंक्शन जिसे उनके समय को मापने के लिए कमांड से पहले जोड़ा जा सकता है:

tm() {
  s=$(date +%s)
  $@
  rc=$?
  echo "took $[$(date +%s)-$s] seconds. return code $rc" >&2
  return $rc
}

फिर इसे अपनी स्क्रिप्ट में, या अपनी कमांड लाइन पर उपयोग करें जैसे:

tm the_original_command with all its parameters

यह मिलिसेकंड जोड़ने के लिए लायक होगा, ilke की कोशिश की s=$(date +%s000), निश्चित नहीं कि यह काम करता है।
लोरेटोपरसी

3

यहाँ एलेक्स के उत्तर की भिन्नता है। मुझे केवल मिनट और सेकंड की परवाह है, लेकिन मैं यह भी चाहता था कि यह अलग तरीके से स्वरूपित हो। तो मैंने ऐसा किया:

start=$(date +%s)
end=$(date +%s)
runtime=$(python -c "print '%u:%02u' % ((${end} - ${start})/60, (${end} - ${start})%60)")

1
क्यों होता है पतन? क्या मेरे पास बग है?
एमपॉन्टिलो

3
#!/bin/csh
#PBS -q glean
#PBS -l nodes=1:ppn=1
#PBS -l walltime=10:00:00
#PBS -o a.log
#PBS -e a.err
#PBS -V
#PBS -M shihcheng.guo@gmail.com
#PBS -m abe
#PBS -A k4zhang-group
START=$(date +%s)
for i in {1..1000000}
do
echo 1
done
END=$(date +%s)
DIFF=$(echo "$END - $START" | bc)
echo "It takes DIFF=$DIFF seconds to complete this task..."

7
यह वास्तव में पहले से दिए गए अन्य उत्तरों से अलग कैसे है जो dateस्क्रिप्ट के पहले और बाद में उपयोग करते हैं और उनके बीच अंतर को आउटपुट करते हैं?
एरिक रेनॉफ

2

केवल बैश का उपयोग करके शेल स्क्रिप्ट के एक हिस्से के लिए समय अवधि को मापना और गणना करना संभव है (या संपूर्ण स्क्रिप्ट के लिए बीता हुआ समय):

start=$SECONDS

... # do time consuming stuff

end=$SECONDS

अब आप केवल अंतर को प्रिंट कर सकते हैं:

echo "duration: $((end-start)) seconds."

यदि आपको केवल वृद्धिशील अवधि की आवश्यकता है:

echo "duration: $((SECONDS-start)) seconds elapsed.."

आप एक चर में अवधि को भी स्टोर कर सकते हैं:

let diff=end-start

^ यह उत्तर लोगों है। या अधिक बस: अंत में $ सेकंड। यह एक BILT-IN बैश वैरिएबल है। अन्य सभी उत्तर केवल इस पहिये को फिर से आविष्कार करने के लिए अतिरिक्त काम कर रहे हैं ...
Crossfit_and_Beer

2

व्यक्तिगत रूप से, मैं अपने सभी स्क्रिप्ट कोड को कुछ "मुख्य" फ़ंक्शन में लपेटना पसंद करता हूं:

main () {
 echo running ...
}

# stuff ...

# calling the function at the very end of the script
time main

ध्यान दें कि timeइस परिदृश्य में कमांड का उपयोग करना कितना आसान है । जाहिर है आप स्क्रिप्ट पार्स समय सहित सटीक समय को माप नहीं रहे हैं, लेकिन मुझे यह ज्यादातर स्थितियों में सटीक लगता है।


1
#!/bin/bash
begin=$(date +"%s")

Script

termin=$(date +"%s")
difftimelps=$(($termin-$begin))
echo "$(($difftimelps / 60)) minutes and $(($difftimelps % 60)) seconds elapsed for Script Execution."

1

SECONDSकेवल दूसरे स्तर के ग्रैन्युलैरिटी तक सीमित समय के आधार पर समारोह , किसी भी बाहरी आदेश का उपयोग नहीं करता है:

time_it() {
  local start=$SECONDS ts ec
  printf -v ts '%(%Y-%m-%d_%H:%M:%S)T' -1
  printf '%s\n' "$ts Starting $*"
  "$@"; ec=$?
  printf -v ts '%(%Y-%m-%d_%H:%M:%S)T' -1
  printf '%s\n' "$ts Finished $*; elapsed = $((SECONDS-start)) seconds"
  # make sure to return the exit code of the command so that the caller can use it
  return "$ec"
}

उदाहरण के लिए:

time_it sleep 5

देता है

2019-03-30_17:24:37 Starting sleep 5 2019-03-30_17:24:42 Finished
sleep 5; elapsed = 5 seconds
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.