Ausgabe des Zeitbefehls in Unix in eine Variable in Bash umleiten?

13

Ich möchte nur die Ausgabe eines Zeitbefehls erfassen, dh:

X=$(time ls)

oder

$(time ls) | grep real

Die Zeitfunktion spuckt es jedoch auf die Konsole. Wie mache ich das?

Joshua Enfield
quelle

Antworten:

12

X = `(Zeit ls) 2> & 1 | grep real`

Jason Berg
quelle
Sie brauchen keine Subshell nur für time; Dennis Williamsons Antwort ist in dieser Hinsicht besser.
Musiphil
11

Siehe 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>&-

Die Zeit wird wie "0.000" aussehen, wobei TIMEFORMAT="%R""Echtzeit" verwendet wird.

Bis auf weiteres angehalten.
quelle
Könntest du ein wenig erklären, wie das funktioniert? Ich verwende seit Jahren einen Ausschnitt wie diesen Frachtkultstil. Was ist Stream 3 und 4? und die '-' ?
Sirex
1
@ Sirex: Streams 3 und 4 sind Streams, die vom execBefehl in meiner Antwort unter Verwendung der verfügbaren Dateideskriptoren erstellt wurden. Beliebige verfügbare Dateideskriptoren könnten verwendet werden. Streams 3 und 4 sind Kopien von 1 ( stdout) bzw. 2 ( stderr). Dies ermöglicht, dass die Ausgabe von lsnormal an stdoutund stderrüber 3 und 4 übergeben wird, während die Ausgabe von time(die normalerweise an geht stderr) zum Original stdout(1) umgeleitet und dann in der Variablen unter Verwendung der Befehlssubstitution erfasst wird. Wie Sie in meinem Beispiel sehen können, werden die Dateinamen barund bazauf dem Terminal ausgegeben. ...
Bis auf weiteres angehalten.
1
... Wenn Sie fertig sind, werden die zusätzlichen Streams mit dem Trailing geschlossen -.
Bis auf weiteres angehalten.
4

Die Zeit schreibt ihre Ausgabe eher in STDERR als in STDOUT. Erschwerend kommt hinzu, dass 'time' standardmäßig ein Shell-Befehl ist. Wenn Sie also 'time ls 2> & 1' versuchen, gilt '2> & 1' nur für 'ls'.

Die Lösung wäre wahrscheinlich so etwas wie:

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

Es gibt ausgefallenere Möglichkeiten, dies zu tun, aber das ist der klare / einfache Weg.

Jason
quelle
Ich bin daran interessiert, dies ohne -o zu tun. Kannst du eine der ausgefallenen Methoden posten, an die du gedacht hast :)?
David Doria
0

@Dennis Williamsons Antwort ist großartig, aber es hilft Ihnen nicht, die Ausgabe des Befehls in einer Variablen und die Ausgabe timein einer anderen Variablen zu speichern . Dies ist mit Dateideskriptoren eigentlich nicht möglich.

Wenn Sie aufzeichnen möchten, wie lange die Ausführung eines Programms dauert, können Sie dies tun, indem Sie einfach die Startzeit von der Endzeit subtrahieren. Hier ist ein einfaches Beispiel, das zeigt, wie viele Millisekunden ein Programm benötigt hat:

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

Dies ist nicht ganz so genau wie der timeBefehl, sollte aber für die meisten Bash-Skripte einwandfrei funktionieren.

Leider unterstützt Macs dateBefehl das %NFormat nicht, aber Sie können installieren coreutils( brew install coreutils) und verwenden 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
quelle