Przekierować wyjście polecenia czasu w unixie do zmiennej w bash?

13

Chcę tylko uchwycić wynik polecenia czasu, tj .:

X=$(time ls)

lub

$(time ls) | grep real

Funkcja czasu wyrzuca go jednak na konsolę. Jak mam to zrobic?

Joshua Enfield
źródło

Odpowiedzi:

12

X = `(czas ls) 2> i 1 | grep real`

Jason Berg
źródło
Nie potrzebujesz tylko podpowłoki time; Odpowiedź Dennisa Williamsona jest lepsza pod tym względem.
musiphil
11

Zobacz BashFAQ / 032 .

$ # captures output of command and time
$ time=$( TIMEFORMAT="%R"; { time ls; } 2>&1 )    # note the curly braces

$ # captures the time only, passes stdout through
$ exec 3>&1 4>&2
$ time=$(TIMEFORMAT="%R"; { time ls 1>&3 2>&4; } 2>&1)
bar baz
$ exec 3>&- 4>&-

Czas będzie wyglądał jak „0,000”, przy użyciu TIMEFORMAT="%R"którego będzie to „czas rzeczywisty”.

Wstrzymano do odwołania.
źródło
czy mógłbyś trochę wyjaśnić, jak to działa? Od lat używam takiego fragmentu, jak ten kultowy kult ładunku. Jaki jest strumień 3 i 4? i „-”?
Sirex
1
@Sirex: Strumienie 3 i 4 to strumienie utworzone przez execpolecenie w mojej odpowiedzi przy użyciu dostępnych deskryptorów plików. Można użyć dowolnych dostępnych deskryptorów plików. Strumienie 3 i 4 są odpowiednio kopiami 1 ( stdout) i 2 ( stderr). Pozwala to lsna normalne przejście wyjścia do stdouti stderrprzez 3 i 4, podczas gdy wyjście time(które zwykle przechodzi stderr) jest przekierowywane do oryginału stdout(1), a następnie przechwytywane w zmiennej za pomocą podstawiania poleceń. Jak widać w moim przykładzie, nazwy plików bari bazsą wyprowadzane do terminala. ...
Wstrzymano do odwołania.
1
... Po zakończeniu dodatkowe strumienie są zamykane za pomocą trailing -.
Wstrzymano do odwołania.
4

Czas zapisuje dane wyjściowe do STDERR zamiast STDOUT. Co gorsza, domyślnie „czas” jest wbudowanym poleceniem powłoki, więc jeśli spróbujesz „czas ls 2> i 1”, „2> i 1” dotyczy tylko „ls”.

Rozwiązaniem byłoby prawdopodobnie coś w rodzaju:

/usr/bin/time -f 'real %e' -o OUTPUT_FILE ls > /dev/null 2>&1<br>
REALTIME=$(cat OUTPUT_FILE | cut -f 2 -d ' ')

Jest więcej wymyślnych sposobów na zrobienie tego, ale jest to jasny / prosty sposób.

Jason
źródło
Jestem zainteresowany zrobieniem tego bez -o. Czy możesz napisać jedną z wymyślnych metod, o których myślałeś :)?
David Doria
0

Odpowiedź Dennisa Williamsona jest świetna, ale nie pomaga przechowywać danych wyjściowych polecenia w jednej zmiennej, a danych wyjściowych timew innej zmiennej. W rzeczywistości nie jest to możliwe przy użyciu deskryptorów plików.

Jeśli chcesz zapisać czas działania programu, możesz to zrobić, odejmując czas rozpoczęcia od czasu zakończenia. Oto prosty przykład, który pokazuje, ile milisekund potrzebował do uruchomienia programu:

START_TIME=$(date +%s%3N)
OUTPUT=$(ls -l)
ELAPSED_TIME=$(expr $(date +%s%3N) - $START_TIME)
echo "Command finished in $ELAPSED_TIME milliseconds"

Nie jest to tak dokładne jak timepolecenie, ale powinno działać idealnie w przypadku większości skryptów bash.

Niestety datepolecenie Maca nie obsługuje tego %Nformatu, ale możesz zainstalować coreutils( brew install coreutils) i użyć gdate:

START_TIME=$(gdate +%s%3N)
OUTPUT=$(ls -l)
ELAPSED_TIME=$(expr $(gdate +%s%3N) - $START_TIME)
echo "Command finished in $ELAPSED_TIME milliseconds"
ndbroadbent
źródło