Usando o tempo em funções bash (não em comandos)

2

Como se pode medir chamadas individuais para funções bash de dentro do arquivo bash.

Eu tenho um programa que eu chamo usando o comando

eclipse -b col_solve.pl -e "myPred"

Esta chamada produz algumas informações, a última das quais é SUCCESS ou FAIL. Eu estou escrevendo um script que é chamado em um monte de arquivos em um diretório, e para cada um desses arquivos, saídas

  • O nome
  • O status (SUCESSO ou FALHA)
  • e o tempo (usuário) necessário para executar.

Esse é o código que eu sei que funciona:

Eu uso isso para obter o status (recuperando a última palavra na saída):

stat=
get_stat ( ){
    stat=$(awk '{print $NF}' <<< $1);
}

Eu uso isso para chamar o programa:

run_eclipse_on ( ){
    get_stat "$(eclipse -b col_solve.pl -e "run(\"$1\")" )";
}

O código problemático é o seguinte:

for i in 'ls $1' ;  #where $1 is the directory containing the files
do
    tps=$(/usr/bin/time -f %U      \ #to get just the user time
         [run_eclipse_on $1/$i] ); # HERE it is! 
    echo $i::$stat::::$tps;  # gives, for ex: file_name::SUCCESS::::0.20
done

A linha culpada é aquela em que a função é chamada. Eu tentei cercá-lo com ', {, [ $ (,' e ". Nada funcionou ...

É mesmo possível ...?

    
por ZakC 10.05.2016 / 17:10

3 respostas

5

Use a time keyword em vez do comando externo. A utilização da palavra-chave permite que você execute time em qualquer comando shell, incluindo chamadas de função, não apenas na execução de um programa. Você pode controlar o formato de saída até certo ponto através da TIMEFORMAT variable .

TIMEFORMAT=%2U
time run_eclipse_on …
echo "$i::$stat"

A saída time é impressa em sua própria linha. Bash permite um truque: você pode alterar TIMEFORMAT durante o comando, para que você possa colocar mais coisas lá.

time { run_eclipse_on …; TIMEFORMAT="${i//%/%%}::${stat//%/%%}::%2U"; }

A saída de time é impressa no erro padrão. Se você precisar disso na saída padrão, apenas redirecione com 2>&1 . Isso também redirecionará qualquer comando impresso no stderr. Para preservar o stderr, você pode fazer algumas arquivo descritor de embaralhar .

{ time { {
      run_eclipse_on …;
      TIMEFORMAT=$stat::%2U;
    } 2>&3; } 2>&1; } 3>&2
    
por 11.05.2016 / 01:45
0

Parece que você quer algo assim:

#!/bin/bash

for f in "$1"/*; do
  time eclipse -b col_solve.pl -e "$f" | tail -n 1
done

Não use funções em scripts de shell, a menos que você realmente precise delas. A vantagem de usar scripts de shell é que você pode facilmente orquestrar outras ferramentas. Deixe as ferramentas fazerem o trabalho, não a casca. Basta usar o shell para juntar as outras ferramentas.

Leitura adicional:

por 10.05.2016 / 20:17
-1

Embora não seja o mesmo que "tempo do usuário", se o tempo decorrido for suficiente, outra opção é salvar os horários de início e término e calcular o tempo decorrido em sua chamada de função. A função timer listada aqui torna isso mais fácil.

Reproduzindo a função aqui para facilitar a referência:

# Elapsed time.  Usage:
#
#   t=$(timer)
#   ... # do something
#   printf 'Elapsed time: %s\n' $(timer $t)
#      ===> Elapsed time: 0:01:12
#
#
#####################################################################
# If called with no arguments a new timer is returned.
# If called with arguments the first is used as a timer
# value and the elapsed time is returned in the form HH:MM:SS.
#
function timer()
{
    if [[ $# -eq 0 ]]; then
        echo $(date '+%s')
    else
        local  stime=$1
        etime=$(date '+%s')
        if [[ -z "$stime" ]]; then stime=$etime; fi
        dt=$((etime - stime))
        ds=$((dt % 60))
        dm=$(((dt / 60) % 60))
        dh=$((dt / 3600))
        printf '%d:%02d:%02d' $dh $dm $ds
    fi
}

No seu caso, você incluiria essa função e, em seguida:

for i in *
do
    t=$(timer)
    run_eclipse_on $i
    elapsed=$(timer $t)
    echo $i::$stat::::$elapsed  # gives, for ex: file_name::SUCCESS::::0:00:03
done
    
por 10.05.2016 / 19:03