Записать вывод `time` в файл, зачем нужны скобки?

18

timeпишет в stderr, поэтому можно предположить, что добавление 2>&1в командную строку должно направить свой вывод stdout. Но это не работает

test@debian:~$ cat file 
one two three four
test@debian:~$ time wc file > wc.out 2>&1

real    0m0.022s
user    0m0.000s
sys     0m0.000s
test@debian:~$ cat wc.out 
 1  4 19 file

Только с круглыми скобками это работает:

test@debian:~$ (time wc file) > wc.out 2>&1
test@debian:~$ cat wc.out 
 1  4 19 file

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

Зачем нужны скобки в этом случае? Почему не time wcинтерпретируется как одна команда?

волк-Revo-кошка
источник
3
Обратите внимание, что результаты будут отличаться в зависимости от того, timeявляется ли ключевое слово shell, или /usr/bin/time. Здесь может быть несколько наборов дескрипторов (оболочки и те, которые прикреплены к timeпроцессу). И давайте не будем забывать о тех, которые подразумеваются под ()раковиной. (в ожидании специалиста по bash : p)
Джон У. Х. Смит

Ответы:

24

В ksh, bashи zsh, timeэто не команда (встроенная или нет), это зарезервированное слово на языке, подобном forили while.

Используется для определения времени конвейера 1 .

В:

time for i in 1 2; do cmd1 "$i"; done | cmd2 > redir

У вас есть специальный синтаксис, который говорит оболочке запустить эту конвейерную линию:

for i in 1 2; do cmd1 "$i"; done | cmd2 > redir

И сообщить статистику времени для этого.

В:

time cmd > output 2> error

Это то же самое, что вы синхронизации с cmd > output 2> errorкомандой, и статистика синхронизации до сих пор идут на STDERR оболочки.

Тебе нужно:

{ time cmd > output 2> error; } 2> timing-output

Или:

exec 3>&2 2> timing-output
time cmd > output 2> error 3>&-
exec 2>&3 3>&-

Для перенаправления stderr оболочки timing-outputдо использования конструкции времени (опять же, не команды ) (здесь до времени cmd > output 2> error 3>&-).

Вы также можете запустить эту timeконструкцию в подоболочке с перенаправленным stderr:

(time cmd > output 2> error) 2> timing-output

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

У большинства систем также есть timeкоманда. Вы можете вызвать его, отключив timeключевое слово. Все, что вам нужно сделать, это как-то процитировать это ключевое слово, так как ключевые слова распознаются как таковые только в буквальном смысле.

'time' cmd > output 2> error-and-timing-output

Но остерегайтесь формат может быть различным и STDERR обоих timeи cmdбудут объединены в error-and-timing-output.

Кроме того, timeкоманда, в отличие от timeконструкции, не может синхронизировать конвейеры или составные команды или функции или встроенные функции оболочки ...

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


1 Обратите внимание, что в нем bashесть (что можно рассматривать как) ошибка, из-за которой time (cmd) 2> file(но не, time cmd | (cmd2) 2> fileнапример) перенаправляется вывод времени наfile

Стефан Шазелас
источник
Что ж, я часто подчеркиваю, что timeэто ключевое слово, а не встроенная оболочка.
cuonglm
Спасибо за совет по использованию 'time'для получения исполняемого файла - удобнее, чем писать /usr/bin/time(или даже command time:-)).
Алексис
@alexis также \time.
ctrl-alt-delor
7

Там нет команды с именем time wc, timeи wcотдельные слова в оболочке.

Теперь часто называются две отдельные программыtime , одна из которых является ключевым словом оболочки, другая - внешней командой . В оболочках, которые timeявляются ключевым словом оболочки, при вводе time wc ...команды оболочка использовала свое ключевое слово timeвместо утилиты внешнего времени .

Когда оболочка использует timeключевое слово, ей не нужно выполнять fork () нового процесса, текущий timeстандарт и стандартная ошибка не изменяются. Часть перенаправления в:

time wc file > wc.out 2>&1

влияет wcтолько.

Когда вы используете составную команду(list) :

(time wc file) > wc.out 2>&1

оболочка работала time wc fileвнутри подоболочки, (time wc file)считалась одной командой, а часть перенаправления влияет на ее стандартный вывод и стандартную ошибку, которая теперь включает в себя timeи wc.


Вы можете добиться того же эффекта без затрат на создание нового процесса, используя другую форму группирования {list;}:

{time wc file;} > wc.out 2>&1

Если вы используете external time, то вы не столкнетесь с этой проблемой, потому что она была запущена в новом процессе:

/usr/bin/time wc file > wc.out 2>&1
cuonglm
источник
Есть ли практическая разница между использованием timeи /usr/bin/time? Исполняемые файлы называются функционально одинаковыми?
Хашим
2

Потому timeчто вы выполняете это встроенный в Bash. Bash обрабатывает его таким особым образом.

Если вы будете использовать настоящий timeдвоичный файл, он будет действовать именно так, как вы ожидаете:

/usr/bin/time wc file > wc.out 2>&1

Хотя вывод этого времени немного другой:

 $ /usr/bin/time wc file > wc.out 
0.00user 0.00system 0:00.00elapsed ?%CPU (0avgtext+0avgdata1900maxresident)k
0inputs+8outputs (0major+82minor)pagefaults 0swaps
порыв
источник
9
Если бы это было встроено, это не было бы проблемой. Проблема в том, что это ключевое слово в языке. time cmd > outputраз cmd > outputкоманда, и time foo | barраз foo | bar.
Стефан Шазелас
1

Это не timeто, что пишет информацию о времени. Встроенная команда timeзаставляет оболочку писать это после завершения команды. Но перенаправление влияет только на команду.

В (time ...)случае если перенаправление применяется ко всей подоболочке.

Хауке Лагинг
источник
0

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

Использование скобок переводит всю команду в дочернюю оболочку, чей stderr может быть перенаправлен.

использование фигурных скобок дает похожий результат без фактического запуска подоболочки

  { time who ; } > /tmp/timwho >& /tmp/xx 

(да, вам нужна точка с запятой)

darkonc
источник