it-swarm-tr.com

Program yürütme süresi nasıl ölçülür ve bir değişkenin içinde nasıl saklanır

Bash (v4 +) komut dosyasındaki belirli işlemlerin ne kadar sürdüğünü öğrenmek için, time komutunun "ayrı ayrı" komutundan çıktıyı ayrıştırmak ve (sonuçta) bir Bash değişkeni (let VARNAME=...).

Şimdi time -f '%e' ... (daha doğrusu command time -f '%e' ... Bash yerleşik nedeniyle), ancak zaten çalıştırılan komutun çıktısını yeniden yönlendirdiğim için time komutunun çıktısını nasıl yakalayacağım konusunda gerçekten kayboldum. Temelde buradaki sorun çıktıyı ayırmak için/time yürütülen komutların çıktısından.

Ne istediğim işlevsellik bir komut başlatma ve tamamlanması arasında saniye (tamsayı) süre miktarını sayma olduğunu. time komutu veya ilgili yerleşik olması gerekmez.


Düzenle: Aşağıdaki iki yararlı cevap göz önüne alındığında, iki açıklama eklemek istedim.

  1. Yürütülen komutun çıktısını atmak istemiyorum, ancak stdout veya stderr ile bitip bitmeyeceği gerçekten önemli olmayacak.
  2. Dolaylı olana (yani, ara dosyalarda saklamak yerine çıktıyı doğrudan yakalamak) doğrudan bir yaklaşımı tercih ederim.

date kullanan çözüm şimdiye kadar istediğime yakın geliyor.

65
0xC0000022L

time çıktısını var değerine almak için aşağıdakileri kullanın:

[email protected] $ mytime="$(time ( ls ) 2>&1 1>/dev/null )"
[email protected] $ echo "$mytime"

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

Ayrıca yalnızca tek bir zaman türü isteyebilirsiniz, ör. utime:

[email protected] $ utime="$( TIMEFORMAT='%lU';time ( ls ) 2>&1 1>/dev/null )"
[email protected] $ echo "$utime"
0m0.000s

Zamanı almak için date +%s.%N, bu yüzden yürütmeden önce ve sonra alın ve farkını hesaplayın:

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

Bash'da, time yapısının çıktısı standart hatasına gider ve etkilediği boru hattının standart hatasını yeniden yönlendirebilirsiniz. Şimdi çıktısına ve hata akışlarına yazan bir komutla başlayalım: sh -c 'echo out; echo 1>&2 err'. Komutun hata akışını time çıktısıyla karıştırmamak için, komutun hata akışını geçici olarak farklı bir dosya tanımlayıcıya aktarabiliriz:

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

Bu, out ila fd 1, err ila fd 3 ve süreleri fd 2 yazar:

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

Fd 2'de err olması ve fd 3'te zamanların olması daha hoş olurdu, bu yüzden onları takas ediyoruz, çünkü bu iki dosya tanımlayıcısını değiştirmenin doğrudan bir yolu yok:

{ { { 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:/')

Bu, komutun çıktısını nasıl sonradan işleyebileceğinizi gösterir, ancak hem komutun çıktısını hem de zamanlarını yakalamak istiyorsanız, daha fazla çalışmanız gerekir. Geçici bir dosya kullanmak bir çözümdür. Aslında, hem komutun standart hatasını hem de standart çıktısını yakalamanız gerekiyorsa tek güvenilir çözümdür. Ancak, aksi takdirde, tüm çıktıyı yakalayabilir ve time'nin öngörülebilir bir biçime sahip olmasından yararlanabilirsiniz (time -pPOSIX biçimi veya bash'a özgü TIMEFORMAT değişkenini) almak için.

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*}

Yalnızca duvar saati ile ilgileniyorsanız, date öncesi ve sonrası çalıştırmak basit bir çözümdür (harici komutu yüklemek için harcanan ekstra zaman nedeniyle biraz daha kesin değilse).

bash içindeyseniz (sh değil) ve ikinci saniyeden daha düşük bir doğruluğa ihtiyacınız yoksa, date çağrısını tamamen atlayabilir ve fazladan yumurtlamadan yapabilirsiniz. birleştirilmiş çıktıyı ayırmak zorunda kalmadan ve çıktıyı herhangi bir komuttan yakalayıp ayrıştırmak zorunda kalmadan işler:

# 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.
8
sanpath

Zamanla, komut çıkışı stdout'ta ve zaman stderr'de ortaya çıkar. Yani, onları ayırmak için şunları yapabilirsiniz:

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

Ama şimdi zaman bir dosyada. Bash'in stderr'ı doğrudan bir değişkene koyabildiğini sanmıyorum. Komutun çıktısını bir yere yönlendirmek sakıncası yoksa şunları yapabilirsiniz:

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

Bunu yaptığınızda, komutun çıktısı outputfile olur ve çalışması için gereken süre $FOO.

7
marinus

OSX'deyken önceki yanıtları bir araya getirme

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

beğenebilirsin

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"
}
4
loretoparisi

Bu amaçla, Kabuk ve Kabuktan çalıştırılan işlemler için biriken kullanıcı ve sistem sürelerini yazdıran times içinde time (bash yerine) kullanmak daha iyidir, örnek kullanın:

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

Görmek: help -m times daha fazla bilgi için.

4
kenorb

Yüklemek /bin/time (Örneğin. pacman -S time)

Yani -f bayrağı:

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

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

Aslında kullanabilirsiniz:

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

Ve istediğinizi elde edin - değişkente zaman (örnek %e gerçek geçen süre için, diğer seçenekler için man time):

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

echo "$variable"
1

Tıpkı yukarıdaki ifadelerle çalışırken ve özellikle Grzegorz'un cevabını akılda tutarak, bir baş gibi. Ubuntu 16.04 Xenial sistemimde şu iki sonucu gördüğüme şaşırdım:

$ 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

Ayarlanmış takma adım yok ve bu yüzden bunun neden olduğunu bilmiyorum.

1
Paul Pritchard

bunu deneyin, bağımsız değişkenlerle basit bir komut çalıştırır ve $ real $ user $ sys zamanlarını koyar ve çıkış kodunu korur.

Ayrıca, alt kabukları çatallamaz veya gerçek kullanıcı sistemi dışındaki herhangi bir değişkeni ezmez ve aksi takdirde komut dosyasının çalışmasına müdahale etmez.

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

örneğin.

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

not: bileşenleri bir alt kabukta çalıştırılan bir boru hattının değil, yalnızca basit komutun çarpı

Bu sürüm, 3 kez alması gereken değişkenlerin adını $ 1 olarak belirlemenizi sağlar:

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

örneğin.

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

ve zamanlar çiğnemekten kaçınmak için tekrarlanan olarak çağrılırsa yararlı olabilir; ama sonra r u s vb kullanımlarında yerel ilan edilmelidir.

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

0
Sam Liddicott