«grep» не работает с «time»?

«grep» не работает с «time»?

Почему time ls | grep realвыводится это

real    0m0.002s
user    0m0.000s
sys     0m0.002s

вместо того, чтобы просто

real    0m0.002s

Если я наберу

echo -e 'real\t0m0.002s\nuser\t0m0.000s\nsys\t0m0.002s\n' | grep real

Я получаю то, что ожидаю, т.е.

real    0m0.002s

Я обнаружил, что это работает.

(time ls)  2>&1 > /dev/null | grep real

Что делает эта команда?

решение1

Почему time ls | grep realне работает так, как ожидалось.

timeявляется bashзарезервированным словом и ведет себя иначе, чем /usr/bin/time.

Если зарезервированное слово времени предшествует конвейеру, сообщается прошедшее время, а также время пользователя и системы, затраченное на его выполнение.когда заканчивается трубопровод.

Источникbash(1): GNU Bourne-Again SHell - страница руководства Linux

Кроме того, timeвыводит данные в стандартный поток ошибок, а не в стандартный поток вывода.

Используйте следующую команду:

(time ls) 2>&1 >/dev/null | grep real 

Примечания:

  • Оператор (and )объединяет команды timeи lsвместе (чтобы эти команды оценивались в первую очередь)

  • 2>&1 >/dev/nullсначала перенаправляет stderr в stdout (который является каналом), а затем перенаправляет stdout в /dev/null.

    Таким образом, stderr направляется в канал, а stdout никуда не направляется.


Дальнейшее чтение

решение2

Да, это работает, но требует небольшого перенаправления ввода-вывода :)

$ exec 3>&1 4>&2
{ time sleep 1 1>&3 2>&4; } 2>&1 |
    grep 'real'    
exec 3>&- 4>&-

Выход :

real    0m1,003s

Читатьbash FAQ#32иУчебник по перенаправлению ввода-вывода


Более простой способ:

$ TIMEFORMAT=%R
$ time sleep 1
1,003

решение3

Здесь есть две проблемы.

Первое и самое важное: «time» отправляет свой вывод в stderr (стандартный поток ошибок), а не в stdout, чтобы он не был перехвачен обычными командами перенаправления, если только вы не примете специальных мер.

Во-вторых, time — это не обычная программа, а специальная встроенная команда, интерпретируемая непосредственно оболочкой (для оболочек типа bash, csh, tcsh и т. д.). Таким образом, она работает нестандартным образом и измеряет время всей остальной части командной строки (если только вы не используете очень необычную оболочку).

Итак, чтобы получить желаемый результат (используя bash), вам нужно использовать:

(time ls) 2>&1 | grep real

Это запустит «ls» в подоболочке и хронометрирует ее [(время ls)] , отправить стандартную ошибку на стандартный вывод[ 2>&1 ], а затем отправить стандартный вывод в "grep" [|grep].

Последняя часть, которую вы использовали ">?dev/null" отбрасывает обычный вывод самой команды ls, в случае если он включал слово "real".

решение4

Похоже, что timeзапись производится непосредственно в консоль, а не в stdout, что означает, что вывод команды или конвейера не изменяется при добавлении time.

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

Связанный контент