Борьба за разбор команды времени (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'
чтобы зафиксировать формат.