Борьба за разбор команды времени (bash)

Я изо всех сил пытаюсь разобрать вывод команды времени в bash - и даже не останавливать ее при распечатке своего вывода, когда я его вызываю. Это мой тестовый код:

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

В настоящее время выдает:

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

Итак, кажется, что значение, назначенное $TIME, является пустой строкой в ​​начале распечатки времени. Мне нужно получить значение секунд sys линии, то есть "0.005". Я уверен, что у меня будут только секунды, поэтому мне ничего не нужно до "м", однако секундная часть может быть в виде xx.xxx, если она идет >= 10 секунд. В настоящее время я понятия не имею, как подавить вывод "времени", захватить все это вместо пустой строки и не анализировать, чтобы получить нужные значения.

Любая помощь будет высоко оценена...

Ответ 1

Если вы используете Bash builtin time, вы можете управлять его выходом, установив переменную TIMEFORMAT:

TIMEFORMAT=%R

и вам не придется выполнять какой-либо разбор, так как это приведет к тому, что time будет выводить только количество секунд.

и используйте это:

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

или один из других методов из BashFAQ/032.

Ответ 2

Прежде всего, данные, которые вы пытаетесь захватить, записываются в стандартную ошибку. Но захват этого вывода в этом случае довольно сложный.

time является исполняемым (в /usr/bin), а также встроенной командой оболочки в bash и других оболочках. Когда вы выполняете time без указания /usr/bin/time, вы выполняете встроенную команду в bash. Это затрудняет работу с выходом, поскольку bash не рассматривает его как обычную программу; это специальная встроенная функция, написанная bash.

Зная это, и глядя на страницу руководства для time(1), я вижу, что данные, которые вы пытаетесь захватить из time, выводятся в stderr. Поэтому для этого я должен выполнить /usr/bin/time следующим образом:

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

Это копирует стандартный поток ошибок в стандартную версию, а затем перенаправляет то, что обычно соответствует стандарту на /dev/null. Стандартная ошибка, однако, по-прежнему будет стандартным, поскольку она была дублирована перед перенаправлением. Реверсирование их порядка не будет работать. (Да, это сбивает с толку.)

К сожалению, /usr/bin/time является менее точным в своем выходе:

    0.00 real         0.00 user         0.00 sys

В качестве альтернативы вы можете использовать 2 суб-оболочки:

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

Это приведет к повторной записи того, что записано в стандартную ошибку на второй подоболочке в первом, что позволяет вам записывать вывод. См. http://www.tldp.org/LDP/abs/html/subshells.html для получения дополнительных сведений о суб-оболочках.

Ответ 3

Хотя решения зависают вокруг одной и той же логики, но все же я не смог найти перечисленные ниже, поэтому другая версия решения:

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

Ответ 4

Команда time выводит информацию о времени в STDERR, которую вы не захватываете или не перенаправляете. Поэтому во время назначения эта информация выводится на консоль, а переменная $TIME получает STDOUT команды - которую вы перенаправили на /dev/null, поэтому она пуста.

Возможно, вам стоит попытаться захватить STDERR команды?

Ответ 5

Я хотел опубликовать это как комментарий, но это было бы слишком долго. Я хотел представить другой несколько иной способ получения данных.

Вы можете использовать два суб-оболочки, чтобы получить результат времени как поток, используя /bin/sh, а не /usr/bin/time, чтобы получить время выполнения. Я полагаю, вы можете заменить time на /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

Обратите также внимание на то, что, как представляется, существует разница в том, как он будет выдавать результат. Иногда он находится в этом формате, и иногда он находится в таком формате:

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

Не уверен в этом, что определяет то или другое.

Конечно, вы можете использовать, например,

TIMEFORMAT='%3R' 

чтобы зафиксировать формат.