Я хочу timeкоманду, которая состоит из двух отдельных команд с одним выводом трубопровода к другому. Например, рассмотрим два сценария ниже:
$ cat foo.sh
#!/bin/sh
sleep 4
$ cat bar.sh
#!/bin/sh
sleep 2
Теперь, как я могу timeсообщить о потраченном времени foo.sh | bar.sh(и да, я знаю, что канал здесь не имеет смысла, но это всего лишь пример)? Это работает, как и ожидалось, если я запускаю их последовательно в подоболочке без трубопровода:
$ time ( foo.sh; bar.sh )
real 0m6.020s
user 0m0.010s
sys 0m0.003s
Но я не могу заставить его работать при обвязке:
$ time ( foo.sh | bar.sh )
real 0m4.009s
user 0m0.007s
sys 0m0.003s
$ time ( { foo.sh | bar.sh; } )
real 0m4.008s
user 0m0.007s
sys 0m0.000s
$ time sh -c "foo.sh | bar.sh "
real 0m4.006s
user 0m0.000s
sys 0m0.000s
Я прочитал аналогичный вопрос ( Как запустить время на нескольких командах И записать вывод времени в файл? ), А также попробовал автономный timeисполняемый файл:
$ /usr/bin/time -p sh -c "foo.sh | bar.sh"
real 4.01
user 0.00
sys 0.00
Это даже не работает, если я создаю третий скрипт, который запускает только канал:
$ cat baz.sh
#!/bin/sh
foo.sh | bar.sh
И тогда время, которое:
$ time baz.sh
real 0m4.009s
user 0m0.003s
sys 0m0.000s
Интересно, что он не выглядит так, как будто timeзавершается, как только первая команда выполнена. Если я изменю bar.shна:
#!/bin/sh
sleep 2
seq 1 5
И timeопять же, я ожидал, что timeвывод будет напечатан раньше, seqно это не так:
$ time ( { foo.sh | bar.sh; } )
1
2
3
4
5
real 0m4.005s
user 0m0.003s
sys 0m0.000s
Похоже time, не считается время, которое потребовалось для выполнения, bar.shнесмотря на ожидание его завершения перед печатью своего отчета 1 .
Все тесты выполнялись в системе Arch и использовали выпуск bash 4.4.12 (1). Я могу использовать bash только для проекта, частью которого он является, так что даже если zshили какая-то другая мощная оболочка сможет обойти его, это не будет для меня жизнеспособным решением.
Итак, как я могу получить время, которое потребовалось для запуска набора конвейерных команд? И, хотя мы на это, почему это не работает? Похоже, что timeсразу выходит, как только первая команда закончена. Зачем?
Я знаю, что могу получить индивидуальные времена с чем-то вроде этого:
( time foo.sh ) 2>foo.time | ( time bar.sh ) 2> bar.time
Но я все еще хотел бы знать, возможно ли рассчитать все это как одну операцию.
1 Похоже, что это не проблема с буфером, я попытался запустить сценарии с unbufferedи, stdbuf -i0 -o0 -e0и числа все еще печатались до timeвывода.