প্রোগ্রাম কার্যকর করার সময় কীভাবে পরিমাপ করা যায় এবং এটি একটি ভেরিয়েবলের মধ্যে সঞ্চয় করতে হয়


61

বাশ (v4 +) স্ক্রিপ্টের মধ্যে নির্দিষ্ট অপারেশনগুলি কতক্ষণ সময় নেয় তা জানতে, আমি time"পৃথকভাবে" কমান্ড থেকে আউটপুটকে পার্স করতে এবং (শেষ পর্যন্ত) এটি একটি ব্যাশ ভেরিয়েবলের মধ্যে ক্যাপচার করতে চাই ( let VARNAME=...)।

এখন আমি ব্যবহার করছি time -f '%e' ...(বা বরং command time -f '%e' ...অন্তর্নির্মিত ব্যাশের কারণে), তবে যেহেতু আমি ইতিমধ্যে এক্সিকিউটড কমান্ডের আউটপুটটি পুনর্নির্দেশ করেছি আমি কমান্ডের আউটপুট ক্যাপচার করতে যাব সে সম্পর্কে আমি সত্যিই হারিয়ে ফেলেছি time। মূলত এখানে সমস্যা হল আউটপুট আলাদা করতে এর timeমৃত্যুদন্ড কার্যকর কমান্ড (গুলি) আউটপুট থেকে।

আমি যা চাই তা হ'ল একটি আদেশ শুরু করার এবং এটির সমাপ্তির মধ্যে সেকেন্ডে (পূর্ণসংখ্যার) সময় পরিমাণ গণনা করার কার্যকারিতা ality এটি timeকমান্ড বা সংশ্লিষ্ট অন্তর্নির্মিত হতে হবে না।


সম্পাদনা করুন: নীচে দুটি দরকারী উত্তর দেওয়া, আমি দুটি ব্যাখ্যা যোগ করতে চেয়েছিলেন।

  1. আমি এক্সিকিউটেড কমান্ডের আউটপুট ফেলে দিতে চাই না, তবে এটি stdout বা stderr এ শেষ হয় কিনা তা আসলেই কিছু যায় আসে না।
  2. আমি একটি অপ্রত্যক্ষ একের চেয়ে প্রত্যক্ষ পদ্ধতির পছন্দ করতে চাই (অর্থাত্ মধ্যবর্তী ফাইলগুলিতে এটি সংরক্ষণের বিপরীতে সরাসরি আউটপুট ধরা)।

dateএখনও পর্যন্ত ব্যবহার করা সমাধানটি আমার যা ইচ্ছা তা বন্ধ হয়ে যায়।


তথ্য পেতে এবং এটি পরিচালনা এখনও লেট এটা স্বাভাবিকভাবে চালানো ব্যবহার করে একটি সি প্রোগ্রামে এটা করতে হবে সবচেয়ে সরাসরি উপায় fork(), execvp()এবং wait3()/wait4()। সময় এবং বন্ধুরা এটিই শেষ পর্যন্ত করছে। কোনও ফাইল বা অনুরূপ পদ্ধতির দিকে পুনঃনির্দেশ না করে ব্যাশ / পার্লে এটি করার একক উপায় সম্পর্কে আমি অবগত নই।
পেঙ্গুইন 359

এখানে সম্পর্কিত একটি প্রশ্ন রয়েছে যা আপনার এখানে আকর্ষণীয় হতে পারে ।
কালেব

@ কালেব: ধন্যবাদ সত্যই আকর্ষণীয়। যাইহোক, আমার উদ্দেশ্যে এটি কোনও স্ক্রিপ্টে করা যথেষ্ট to
0xC0000022L

উত্তর:


85

timeএকটি ভেরুতে আউটপুট পেতে নিম্নলিখিত ব্যবহার করুন:

usr@srv $ mytime="$(time ( ls ) 2>&1 1>/dev/null )"
usr@srv $ echo "$mytime"

real    0m0.006s
user    0m0.001s
sys     0m0.005s

আপনি কেবলমাত্র একক সময়ের জন্য যেমন ইউটিউম:

usr@srv $ utime="$( TIMEFORMAT='%lU';time ( ls ) 2>&1 1>/dev/null )"
usr@srv $ echo "$utime"
0m0.000s

আপনি যে সময়টি ব্যবহার করতে পারেন তা পেতে date +%s.%N, সুতরাং মৃত্যুদন্ড কার্যকর করার আগে এবং পরে এটি গ্রহণ করুন এবং ভিন্নতার গণনা করুন:

START=$(date +%s.%N)
command
END=$(date +%s.%N)
DIFF=$(echo "$END - $START" | bc)
# echo $DIFF

4
আমি যদিও কমান্ড থেকে আউটপুটটি ফেলে দিতে চাইনি। সুতরাং আমি অনুমান করি যে আপনার তৃতীয় কোড ব্লকটি আমি যা মনে রেখেছিলাম তার থেকে নিকটতম। যদিও আমি শেষটি লিখি DIFF=$((END-START)), পাটিগণিতের অভিব্যক্তিটি ব্যবহার করে। :) ... উত্তরের জন্য ধন্যবাদ. +1
0xC0000022L

1
@ STATUS_ACCESS_DENIED: বাশ ফ্লোটিং পয়েন্ট পাটিগণিত করেন না, সুতরাং আপনি যদি দ্বিতীয় রেজোলিউশনের চেয়ে ভাল চান ( .%Nবিনফালসের কোডে), আপনার হয় প্রয়োজন bcবা ফ্যানসিয়ার গণনা প্রয়োজন ।
গিলস 21

@ গিলস: আমি জানি। আমি আমার প্রশ্নে লিখেছি পূর্ণসংখ্যা ঠিক আছে। দ্বিতীয় চেয়ে উচ্চতর রেজোলিউশন করার দরকার নেই। তবে ধন্যবাদ, তারিখের অনুরোধটি পরিবর্তন করতে হবে। যদিও আমি বুঝতে পেরেছিলাম।
0xC0000022L

6
এফওয়াইআই, তারিখের ফর্ম্যাট% N ম্যাক ওএস এক্সে কাজ করছে বলে মনে হচ্ছে না, এটি কেবল "এন" ফিরিয়ে দেয়। উবুন্টু ঠিক আছে।
ডেভিড 21

নোট করুন যে সময় time (cmd) 2> somethingনির্ধারণের সময়কে আউটআরেক্ট করার সময় এটি কাজ করে fileনা (ডকুমেন্টেশন অনুসারে), অন্য শেলগুলিতে যেখানে timeকোনও কীওয়ার্ড নেই এবং এটি বাগ হিসাবে বিবেচিত হতে পারে । এর ভবিষ্যতের সংস্করণগুলিতে এটি কাজ না করায় আমি তার উপর নির্ভর করব না bash
স্টাফেন চেজেলাস

17

ব্যাশে, timeকনস্ট্রাক্টের আউটপুটটি তার স্ট্যান্ডার্ড ত্রুটিতে চলে যায় এবং আপনি যে পাইপলাইনটিকে প্রভাবিত করেন এটির স্ট্যান্ডার্ড ত্রুটি পুনর্নির্দেশ করতে পারেন। সুতরাং আসুন কমান্ড যে তার আউটপুট এবং ত্রুটি streamas লিখেছেন সাথে শুরু করা যাক sh -c 'echo out; echo 1>&2 err'। কমান্ডের ত্রুটি স্ট্রিমটি আউটপুটটির সাথে মিশ্রিত না করার জন্য time, আমরা সাময়িকভাবে কমান্ডের ত্রুটি প্রবাহকে অন্য একটি ফাইল বর্ণনাকারীর দিকে রূপান্তর করতে পারি:

{ time -p sh -c 'echo out; echo 1>&2 err' 2>&3; }

এটি outএফডি 1, errএফডি 3 এবং এফডি 2-তে লিখেছে :

{ time -p sh -c 'echo out; echo 1>&2 err' 2>&3; } \
    3> >(sed 's/^/ERR:/') 2> >(sed 's/^/TIME:/') > >(sed 's/^/OUT:/')

errএফডি 2 এবং এফডি 3-তে সময় রাখা আরও সুখকর হবে , সুতরাং আমরা এগুলি অদলবদল করি যা জটিল umbers

{ { { time -p sh -c 'echo out; echo 1>&2 err' 2>&3; } 3>&2 2>&4; } 4>&3; } 3> >(sed 's/^/TIME:/') 2> >(sed 's/^/ERR:/') > >(sed 's/^/OUT:/')

এটি আপনাকে কমান্ডের আউটপুট পোস্টপ্রোসেস করতে পারে তা দেখায় তবে আপনি যদি কমান্ডের আউটপুট এবং তার সময় উভয়ই পেতে চান তবে আপনাকে আরও কঠোর পরিশ্রম করতে হবে। একটি অস্থায়ী ফাইল ব্যবহার করা একটি সমাধান। আসলে, যদি আপনি কমান্ডের স্ট্যান্ডার্ড ত্রুটি এবং এর স্ট্যান্ডার্ড আউটপুট উভয়ই গ্রহণ করতে পারেন তবে এটিই একমাত্র নির্ভরযোগ্য সমাধান। তবে অন্যথায়, আপনি পুরো আউটপুট ক্যাপচার করতে পারেন এবং timeভবিষ্যদ্বাণীযোগ্য ফর্ম্যাট রয়েছে (আপনি যদি পসিক্স ফর্ম্যাট বা ব্যাশ-নির্দিষ্ট ভেরিয়েবলটি time -pপেতে ব্যবহার করেন) তবে আপনি এই সুবিধাটি নিতে পারেন ।TIMEFORMAT

nl=$'\n'
output=$(TIMEFORMAT='%R %U %S %P'; mycommand)
set ${output##*$nl}; real_time=$1 user_time=$2 system_time=$3 cpu_percent=$4
output=${output%$nl*}

যদি আপনি কেবল প্রাচীর ঘড়ির সময় সম্পর্কে যত্নশীল হন তবে dateআগে এবং পরে দৌড়ানো একটি সহজ সমাধান (যদি বাহ্যিক কমান্ডটি লোড করার জন্য অতিরিক্ত সময় ব্যয় করার কারণে কিছুটা আরও ফাঁকি দেওয়া হয়)।


বাহ, অনেক পরীক্ষা করার। বিস্তৃত উত্তরের জন্য অনেক ধন্যবাদ। +1 টি।
0xC0000022L

7

সময়ের সাথে সাথে কমান্ড আউটপুট স্ট্যাডআউটে বেরিয়ে আসে এবং সময় স্টেডারে বের হয়। সুতরাং, এগুলি আলাদা করতে, আপনি এটি করতে পারেন:

command time -f '%e' [command] 1>[command output file] 2>[time output file]

কিন্তু, এখন সময় একটি ফাইলের মধ্যে আছে। আমি মনে করি না যে বাশ স্ট্যাডারকে সরাসরি একটি ভেরিয়েবলে রাখতে সক্ষম। আপনি যদি কমান্ডের আউটপুট কোথাও পুনর্নির্দেশ করতে আপত্তি করেন না তবে আপনি এটি করতে পারেন:

FOO=$((( command time -f '%e' [command]; ) 1>outputfile; ) 2>&1; )

আপনি যখন এটি করেন, কমান্ডের আউটপুট আসবে outputfileএবং এটি চালানোর সময়টি হবে $FOO


1
ওহ, আমি বুঝতে পারি নি আমি timeস্ট্যাডারকে লিখতে জানতাম , তবে আমি বুঝতে পারি নি যে এটি নির্বাহিত কমান্ডের স্টাডাউট এবং স্টাডারকে তার স্টাডআউটে মিশে যাবে। কিন্তু সাধারণত কোন সরাসরি পদ্ধতি নেই (অর্থাত্ মধ্যবর্তী ফাইল ব্যতীত)? +1 টি।
0xC0000022L

3
@ STATUS_ACCESS_DENIED: timeএটির কমান্ড stdoutএবং মেশিন করে না stderr। আমি যেভাবে দেখিয়েছি তা ধরে নিয়েছে যে আপনার কেবল কমান্ডের স্টাডআউট আউটপুট প্রয়োজন। যেহেতু bashকেবল যা বের হবে তা সংরক্ষণ করবে stdout, তাই আপনাকে পুনঃনির্দেশ করতে হবে। আপনি যদি আপনার কমান্ডের স্ট্ডারকে নিরাপদে ফেলে দিতে পারেন: সময়টি সর্বদা স্টডারারের শেষ লাইনে থাকবে। আপনার যদি কমান্ডের আউটপুট উভয় প্রবাহের প্রয়োজন হয় তবে আমি এটিকে অন্য স্ক্রিপ্টে মোড়ানোর পরামর্শ দেব।
মেরিনাস

6

আপনি যদি bash(এবং না sh) থাকেন এবং আপনার যদি দ্বিতীয়-দ্বিতীয় যথার্থতার প্রয়োজন না হয় তবে আপনি কলটি dateপুরোপুরি এড়িয়ে যেতে পারেন এবং কোনও অতিরিক্ত প্রক্রিয়া তৈরি না করে, সম্মিলিত আউটপুট আলাদা না করে এবং আউটপুট ক্যাপচার এবং পার্সিং ছাড়াই করতে পারেন can যে কোনও আদেশ থেকে:

# SECONDS is a bash special variable that returns the seconds since set.
SECONDS=0
mycmd <infile >outfile 2>errfile
DURATION_IN_SECONDS=$SECONDS
# Now `$DURATION_IN_SECONDS` is the number of seconds.

খুশী হলাম। আমি এর আগে কখনোই
সেকেন্ডস

আপনি কি জানেন যে কোন বাশ সংস্করণটির সাথে এটি চালু হয়েছিল?
0xC0000022L

4

সেই উদ্দেশ্যে সম্ভবত ব্যবহার করা ভাল times(এর চেয়ে বেশি time) যাতে bashশেল এবং শেল থেকে চালিত প্রক্রিয়াগুলির জন্য সঞ্চিত ব্যবহারকারী এবং সিস্টেমের সময়গুলি মুদ্রণ করে, উদাহরণস্বরূপ ব্যবহার করুন:

$ (sleep 2; times) | (read tuser tsys; echo $tuser:$tsys)
0m0.001s:0m0.003s

help -m timesআরও তথ্যের জন্য দেখুন:


4

সমস্ত পূর্ববর্তী প্রতিক্রিয়াগুলি একত্রে রাখার সময়, যখন ওএসএক্স থাকে

ProductName:    Mac OS X
ProductVersion: 10.11.6
BuildVersion:   15G31+

আপনি পছন্দ করতে পারেন

microtime() {
    python -c 'import time; print time.time()'
}
compute() {
    local START=$(microtime)
    #$1 is command $2 are args
    local END=$(microtime)
    DIFF=$(echo "$END - $START" | bc)
    echo "$1\t$2\t$DIFF"
}

1

ইনস্টল করুন /bin/time(উদাঃ pacman -S time)

সুতরাং -fপতাকা চেষ্টা করার সময় ত্রুটির পরিবর্তে :

$ time -f %e sleep 0.5
bash: -f: command not found

real    0m0.001s
user    0m0.001s
sys     0m0.001s

আপনি আসলে এটি ব্যবহার করতে পারেন:

$ /bin/time -f %e sleep 0.5
0.50

এবং আপনি যা চান তা পান - ভেরিয়েবলের সময় (উদাহরণস্বরূপ %eআসল সময় কাটানো, অন্যান্য বিকল্পের পরীক্ষার জন্য ব্যবহার করে man time):

#!/bin/bash
tmpf="$(mktemp)"
/bin/time -f %e -o "$tmpf" sleep 0.5
variable="$(cat "$tmpf")"
rm "$tmpf"

echo "$variable"

/usr/bin/timeঅনেক সিস্টেমে
বেসাইল স্টারিনকিভিচ

আপনি যদি নিবিড়ভাবে তাকান তবে আমি আমার প্রশ্নের মধ্যে এটি উল্লেখ করেছি। timeবাশে একটি শেল নির্মিত (এবং সম্ভবত অন্যান্য শাঁস) তবে যতক্ষণ timeএক্সিকিউটেবলের পথটি থাকবে ততক্ষণ আমরা বিল্টিনের বিপরীতে বাহ্যিক কমান্ডটি চালাচ্ছি তা নিশ্চিত PATHকরতে আমরা ব্যবহার command timeকরতে পারি।
0xC0000022L

1

উপরোক্ত বিবৃতিগুলি নিয়ে কাজ করার সময় এবং বিশেষত গ্রজেগোর্জের উত্তরটি মাথায় রাখার সময় যেমন একটি শীর্ষস্থানীয়। আমি আমার উবুন্টু 16.04 জেনিয়াল সিস্টেমে এই দুটি ফলাফল দেখে অবাক হয়েছি:

$ which time
/usr/bin/time

$ time -f %e sleep 4
-f: command not found
real    0m0.071s
user    0m0.056s
sys     0m0.012s

$ /usr/bin/time -f %e sleep 4
4.00

আমার কোনও এলিয়াস সেট নেই এবং তাই আমি জানি না কেন এটি হচ্ছে।


1
timeএটি একটি বিল্টিন শেলও।
বেসিল স্টারিনকিভিচ

আপনি যদি কমান্ডটি চালাচ্ছেন তা নিশ্চিত করতে চান command, আপনি যদি বিল্টিনটি চালাচ্ছেন তা নিশ্চিত করতে চাইলে ব্যবহার করুন builtin। এখানে কোন যাদু নেই। ব্যবহার করুন helpপ্রাপ্তিসাধ্য কমান্ড জিনিসটা বা type <command>জিনিসটা কি ধরনের <command>(যেমন একটি builtin, বাহ্যিক কমান্ড, ফাংশন বা ওরফে)।
0xC0000022L

বেসিল, আপনি বেশ ঠিক বলেছেন। commandকমান্ডটির তাত্পর্য আমি চিহ্নিত করি নি । যা সত্য তা নিশ্চিত করে / ইউএসআর / বিন / সময় বলা হয়। এর অর্থ হল যে নিম্নলিখিত দুটি বিবৃতি সামঞ্জস্যপূর্ণ: $ command time -f %e sleep 4এবং$ /usr/bin/time -f %e sleep
পল প্রিচার্ড

0

এটি ব্যবহার করে দেখুন, এটি আর্গুমেন্টের সাথে একটি সাধারণ কমান্ড চালায় এবং প্রযোজ্য সময়টিকে আসল $ ব্যবহারকারীর জন্য রাখে এবং প্রস্থান কোডটি সংরক্ষণ করে।

এটি সত্যিকারের ব্যবহারকারী ব্যতীত কোনও ভেরিয়েবলকে সাবস্কেল বা পদদলিত করে না এবং অন্যথায় স্ক্রিপ্টের চলতে বাধা দেয় না

timer () {
  { time { "$@" ; } 2>${_} {_}>&- ; } {_}>&2 2>"/tmp/$$.$BASHPID.${#FUNCNAME[@]}"
  set -- $?
  read -d "" _ real _ user _ sys _ < "/tmp/$$.$BASHPID.${#FUNCNAME[@]}"
  rm -f "/tmp/$$.$BASHPID.${#FUNCNAME[@]}"
  return $1
}

যেমন

  timer find /bin /sbin /usr rm /tmp/
  echo $real $user $sys

দ্রষ্টব্য: এটি কেবলমাত্র সাধারণ কমান্ডটি পাইপলাইন নয়, যার উপাদানগুলি একটি সাবশেলে চালিত হয়

এই সংস্করণটি আপনাকে $ 1 হিসাবে ভেরিয়েবলের নামটি নির্দিষ্ট করতে দেয় যা 3 বার গ্রহণ করা উচিত:

timer () {
  { time { "${@:4}" ; } 2>${_} {_}>&- ; } {_}>&2 2>"/tmp/$$.$BASHPID.${#FUNCNAME[@]}"
  set -- $? "$@"
  read -d "" _ "$2" _ "$3" _ "$4" _ < "/tmp/$$.$BASHPID.${#FUNCNAME[@]}"
  rm -f "/tmp/$$.$BASHPID.${#FUNCNAME[@]}"
  return $1
}

যেমন

  timer r u s find /bin /sbin /usr rm /tmp/
  echo $r $u $s

এবং এটি কার্যকর হতে পারে যদি এটি পুনরাবৃত্তি হিসাবে ডাকা শেষ হয়, সময়ে পদদলিত হওয়া এড়াতে; তবে rus ইত্যাদি তাদের ব্যবহারে স্থানীয় হিসাবে ঘোষণা করা উচিত।

http://blog.sam.liddicott.com/2016/01/timeing-bash-commands.html

আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.