Como executar o tempo em vários comandos E gravar a saída do tempo no arquivo?

66

Eu quero executar o timecomando para medir o tempo de vários comandos.

O que eu quero fazer é:

  • Meça o tempo de execução de todos eles somados
  • Grava a timesaída em um arquivo
  • Escreva o STDERRcomando que estou medindo paraSTDERR

O que eu NÃO quero fazer é

  • Escreva os vários comandos em um script separado (por quê? Porque tudo isso já é um script que eu estou gerando programaticamente, e criar OUTRO script temporário seria mais bagunçado do que eu quero)

O que eu tentei até agora:

/usr/bin/time --output=outtime -p echo "a"; echo "b";

Não funciona, timeé executado apenas no primeiro.

/usr/bin/time --output=outtime -p ( echo "a"; echo "b"; )

Não funciona, (é um token inesperado.

/usr/bin/time --output=outtime -p { echo "a"; echo "b"; }

Não funciona, "não existe esse arquivo ou diretório".

/usr/bin/time --output=outtime -p ' echo "a"; echo "b";'

Não funciona, "não existe esse arquivo ou diretório".

time ( echo "a"; echo "b"; ) 2>outtime

Não funciona, pois redireciona tudo STDERRpara outtime; Eu quero apenas a timesaída lá.

E claro,

time --output=outime echo "a";

Não funciona desde então --output=outime: command not found.

Como eu posso fazer isso?

Karel Bílek
fonte

Respostas:

90

Use sh -c 'commands'como o comando, por exemplo:

/usr/bin/time --output=outtime -p sh -c 'echo "a"; echo "b"'
Jim Paris
fonte
2
uma versão mais curta:time -p sh -c 'echo "a"; echo "b"'
Geo
8

Tente o seguinte:

% (time ( { echas z; echo 2 } 2>&3 ) ) 3>&2 2>timeoutput
zsh: command not found: echas
2
% cat timeoutput                                
( { echas z; echo 2; } 2>&3; )  0.00s user 0.00s system 0% cpu 0.004 total

Explicação:

Primeiro, temos que encontrar uma maneira de redirecionar a saída de time. Como timeé um shell embutido, leva a linha de comando completa como o comando a ser medido, incluindo redirecionamentos. Portanto,

% time whatever 2>timeoutput
whatever 2> timeoutput  0.00s user 0.00s system 0% cpu 0.018 total
% cat timeoutput 
zsh: command not found: whatever

[Nota: o comentário de janos implica que este não é o caso bash.] Podemos conseguir o redirecionamento da timesaída de s executando timeem um subshell e, em seguida, redirecionando a saída desse subshell.

% (time whatever) 2> timeoutput
% cat timeoutput 
zsh: command not found: whatever
whatever  0.00s user 0.00s system 0% cpu 0.018 total

Agora redirecionamos com êxito a saída de time, mas sua saída é misturada com a saída de erro do comando que estamos medindo. Para separar os dois, usamos um descritor de arquivo adicional.

Do lado de fora, temos

% (time ... ) 3>&2 2>timeout

Isso significa: o que quer que seja gravado no descritor de arquivo 3, será gerado no mesmo local que o descritor de arquivo 2 (erro padrão) está sendo exibido agora (o terminal). E então redirecionamos o erro padrão para o arquivo timeout.

Então agora temos: tudo escrito em stdout e em fd 3 irá para o terminal, e tudo escrito em stderr irá para o arquivo. O que resta é redirecionar o stderr do comando medido para fd 3.

% (time whatever 2>&3) 3>&2 2>timeout

Agora, para fazer o tempo medir mais de um comando, precisamos executá-los em um subshell (outro!) (Entre parênteses). E para redirecionar a saída de erro de todos eles para o fd 3, precisamos agrupá-los entre colchetes.

Então, finalmente, chegamos a:

% (time ( { whatever; ls } 2>&3 ) ) 3>&2 2>timeoutput

É isso aí.

angus
fonte
Este é um erro de sintaxe em um shell POSIX. Provavelmente um basismo?
Josch
@josch o shell usado aqui é o zsh.
Angus28
6

Não é a resposta correta, mas muito relacionada à pergunta.
Obtenha estatísticas de tempo para vários programas entre parênteses. Separe os comandos com ponto e vírgula.

time ( command1 ; command2 )
Martin T.
fonte
11
Isso é legal. Melhor ainda, use && entre os comandos - assim time ( command1 && command2 )para que, se o primeiro comando falhar; não continuará executando o outro.
bikashg