2010-10-13 16 views
15

Próbuję przeanalizować wynik polecenia time w bashu - i nawet powstrzymać go przed wydrukowaniem jego wyjścia, gdy go wołam. To jest mój kodu testu:Trudno przeanalizować komendę czasu (bash)

#!/bin/bash 
TIME=`time ls -lh > /dev/null` 
echo "Testing..." 
echo $TIME 

to obecnie drukuje:

{blank-line} 
real 0m0.064s 
user 0m0.002s 
sys  0m0.005s 
Testing 
{blank-line} 

Więc wydaje się, że wartości przypisanej do $TIME jest pusty wiersz na początku czasu wydruku. Potrzebuję uzyskać wartość sekundową linii sys - czyli "0.005". Mam gwarancję, że będę miał tylko sekundy, więc nie potrzebuję niczego przed "m" - jednak część sekundowa może być w postaci xx.xxx, jeśli przejdzie> = 10 sekund. Obecnie nie mam pojęcia, jak tłumić wynik "czasu", przechwycić go zamiast pustej linii, ani parsować, aby uzyskać wartości, których potrzebuję.

Każda pomoc będzie mile widziane ...

Odpowiedz

16

Jeśli używasz bash wbudowane time, można kontrolować swoją moc poprzez ustawienie TIMEFORMAT zmiennej:

TIMEFORMAT=%R 

i nie trzeba robić żadnych analizowania ponieważ spowoduje time tylko wyjście liczba sekund.

i użyj:

echo "Testing..." 
TIME=$({ time ls -lh > /dev/null; } 2>&1) 
echo $TIME 

lub jednego z innych technik, BashFAQ/032.

1

W time wyjścia polecenie informacji taktowania do standardowego wyjścia błędów, które nie są przechwytywania lub przekierowywanie. Tak więc przy czasie przypisania ta informacja zostanie wydrukowana na twoją konsolę, podczas gdy zmienna $TIME otrzymuje STDOUT polecenia - które przekierowałeś na /dev/null, więc jest puste.

Być może powinieneś spróbować uchwycić STDERR polecenia?

+0

Ach, nie zdawałem sobie sprawy, że wyjście czasu do 'STDERR'. Jak mogę to przechwycić do zmiennej $ TIME? – Stephen

7

Przede wszystkim dane, które próbujesz przechwycić, są zapisywane jako standardowe błędy. Ale uchwycenie tego wyniku jest w tym przypadku dość trudne.

time jest zarówno plikiem wykonywalnym (w /usr/bin), jak i wbudowanym poleceniem powłoki w powłoce bash i innych powłokach. Po uruchomieniu time bez określania /usr/bin/time, wykonujesz wbudowane polecenie w bash. To sprawia, że ​​trudno jest zrobić rzeczy z wyjściem, ponieważ bash nie traktuje go jak normalnego programu; jest to specjalna wbudowana funkcja napisana przez bash.

Wiedząc o tym i patrząc na stronę podręcznika dla time(1), widzę, że dane, które próbujesz przechwycić z time, są wyprowadzane na stderr. Więc moje obejście tego celu jest bezpośrednio wykonać /usr/bin/time następująco:

TIME=`/usr/bin/time ls -lh 2>&1 >/dev/null` 

ta kopiuje standardowy strumień błędów na standardowe wyjście, a następnie przekierowuje co zwykle idzie na standardowe wyjście do /dev/null. Standardowy błąd jednak nadal będzie standardem, ponieważ został zduplikowany przed przekierowaniem. Odwrócenie ich kolejności nie zadziała. (Tak, to jest mylące.)

Niestety /usr/bin/time jest nieco mniej precyzyjny w swoim wyjściu:

0.00 real   0.00 user   0.00 sys 

Alternatywnie, można użyć 2 sub-muszle, co następuje:

TIME=$((time ls -lh >/dev/null) 2>&1) 

Spowoduje to ponowne zapisanie tego, co jest napisane w standardowym błędzie na drugiej podpowierzchni w pierwszym, co pozwoli na przechwycenie danych wyjściowych. Zobacz http://www.tldp.org/LDP/abs/html/subshells.html, aby uzyskać więcej informacji na temat podpowłok.

+0

Lub użyj tylko jednej pod-powłoki jako 'TIME =" $ ({czas ls -lh>/dev/null;} 2> & 1) ' –

0

Chciałem opublikować to jako komentarz, ale byłoby to za długie. Chciałem przedstawić inny nieco inny sposób uzyskania danych.

Możesz użyć dwóch pod-powłok, aby uzyskać wyjście czasu jako strumienia przy użyciu /bin/sh zamiast /usr/bin/time, aby uzyskać czas wykonania. Wyobrażam sobie, że możesz zastąpić time tutaj z /usr/bin/time.

$ ((time ./print_test.sh > deleteme) 2>&1) > deletemetime 

$ cat deleteme 
test 

$ cat deletemetime 
./print_test.sh > deleteme 0.00s user 0.00s system 86% cpu 0.003 total 

$ ((time ./print_test.sh > deleteme) 2>&1) | sed 's/system/kernel/' 
./print_test.sh > deleteme 0.00s user 0.00s kernel 86% cpu 0.003 total 

Należy również zauważyć, że wydaje się, że występuje różnica w sposobie wytwarzania danych wyjściowych. Czasami jest w tym formacie, a czasami jest w tym formacie:

real 0m0.420s 
user 0m0.385s 
sys  0m0.040s 

Nie jestem pewien, w tym momencie, co decyduje w ten czy inny sposób.

Oczywiście można użyć np.

TIMEFORMAT='%3R' 

w celu poprawienia formatu.

2

Chociaż Solutions oscylować wokół tej samej logiki, ale nadal nie mogę znaleźć Poniżej wymieniono, więc kolejna wersja rozwiązania:

TIME=$(time (ls -lh >/dev/null) 2>&1) 
Powiązane problemy