Redirecționați ieșirea comenzii de timp în unix într-o variabilă în bash? (Administrarea sistemului, Linux, Bash)

Joshua Enfield a intrebat.

Vreau doar să capturez ieșirea unei comenzi de timp, adică:

X=$(time ls)

sau

$(time ls) | grep real

Funcția de timp o scuipă totuși în consolă. Cum pot face acest lucru?

5 răspunsuri
Jason Berg

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

Comentarii

  • Nu aveți nevoie de un subshell doar pentru time; răspunsul lui Dennis Williamson este mai bun în această privință. –  > Por musiphil.
Dennis Williamson

A se vedea 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>&-

Timpul va arăta ca „0.000” folosind TIMEFORMAT="%R" care va fi timpul „real”.

Comentarii

  • Ați putea explica puțin cum funcționează acest lucru? Am folosit un snippet ca acesta în stilul cargo cult de ani de zile. Care sunt fluxurile 3 și 4? Și „-„? –  > Por Sirex.
  • @Sirex: Fluxurile 3 și 4 sunt fluxuri create de către exec comanda din răspunsul meu folosind descriptorii de fișiere disponibili. Ar putea fi folosiți orice descriptori de fișiere disponibili. Fluxurile 3 și 4 sunt copii ale fișierului 1 (stdout) și 2 (stderr), respectiv. Acest lucru permite ieșirea de ls să treacă în mod normal către stdout și stderr prin 3 și 4, în timp ce ieșirea lui time (care trece în mod normal la stderr) este redirecționată către stdout (1) și apoi capturată în variabilă prin substituirea comenzii. După cum puteți vedea în exemplul meu, numele de fișier bar și baz sunt afișate în terminal. … –  > Por Dennis Williamson.
  • … Odată terminate, fluxurile suplimentare sunt închise cu ajutorul funcției de urmărire -. –  > Por Dennis Williamson.
Jason

Time își scrie ieșirea pe STDERR și nu pe STDOUT. Înrăutățind situația, în mod implicit, „time” este o comandă de tip shell builtin, astfel încât, dacă încercați „time ls 2>&1”, „2>&1” se aplică doar la „ls”.

Soluția ar fi, probabil, ceva de genul:

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

Există modalități mai sofisticate de a face acest lucru, dar aceasta este calea clară/simplă.

Comentarii

  • Sunt interesat să fac acest lucru fără -o. Poți să postezi una dintre metodele fanteziste la care te gândeai 🙂 ? –  > Por David Doria.
ndbroadbent

Răspunsul lui @Dennis Williamson este grozav, dar nu te ajută să stochezi ieșirea comenzii într-o singură variabilă, iar ieșirea lui time într-o altă variabilă. Acest lucru nu este de fapt posibil folosind descriptorii de fișiere.

Dacă doriți să înregistrați cât timp durează execuția unui program, ați putea face acest lucru prin simpla scădere a timpului de început din timpul de sfârșit. Iată un exemplu simplu care arată câte milisecunde a durat rularea unui program:

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

Acest lucru nu este la fel de precis ca time dar ar trebui să funcționeze perfect pentru majoritatea scripturilor bash.

Din păcate, Mac’s date nu suportă comanda %N dar puteți instala coreutils (brew install coreutils) și să utilizați gdate:

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

Pithikos

Cea mai curată abordare este de a combina un fișier temporar și utilizarea timpului GNU.

command="sleep 1"
saved_timing=`mktemp`
/usr/bin/time --format="%E real" -o "$saved_timing" $command
elapsed=$(cat "$saved_timing")
echo $elapsed

Acest lucru nu va ocoli ieșirea normală a comenzilor și nici nu trebuie să vă pese de fișier, deoarece acesta va fi șters de unul singur.

Tags:,