Pergunta

Existe uma maneira de incorporar o tempo decorrido parede do último comando em um Bash pronta? Eu estou esperando por algo que ficaria assim:

[last: 0s][/my/dir]$ sleep 10
[last: 10s][/my/dir]$

Fundo

i empregos de trituração de dados longos, muitas vezes funcionam e é útil saber quanto tempo eles levaram para que eu possa estimar quanto tempo vai demorar para futuros empregos. Para tarefas muito regulares, eu vou em frente e gravar esta informação rigorosamente usando técnicas de exploração apropriadas. Para tarefas menos formal, vou apenas prefixar o comando com time.

Seria bom para time automaticamente cada comando interativo e ter a informação tempo impresso em poucos caracteres em vez de 3 linhas.

Foi útil?

Solução

Você pode utilizar este gancho emprestado-zsh para bash: http: // www.twistedmatrix.com/users/glyph/preexec.bash.txt

O sincronismo feito com este gancho (Mac OS X): Use Growl para monitorar shell de longa duração comandos

Outras dicas

Este é o código stand-alone mínimo para conseguir o que deseja:

function timer_start {
  timer=${timer:-$SECONDS}
}

function timer_stop {
  timer_show=$(($SECONDS - $timer))
  unset timer
}

trap 'timer_start' DEBUG
PROMPT_COMMAND=timer_stop

PS1='[last: ${timer_show}s][\w]$ '

Usando suas respostas e alguns outros tópicos, escrevi este pedido que eu quero compartilhar com você. I levou uma imagem em que se podem ver:

  • White: Último código de retorno
  • Green e meio marca de verificação sucesso (código de retorno 0)
  • meios marca Cruz Vermelha e do erro (código de retorno era> 0)
  • (verde ou vermelho): tempo de execução Last Command entre parênteses
  • (verde ou vermelho): tempo de data atual (\ t)
  • (verde se não raiz, Red se root): conectado nome de usuário
  • (Verde): o nome do servidor
  • (azul): o diretório DTD e os US $ habitual

Custom prompt

Aqui está o código para colocar no seu ~ / .bashrc:

function timer_now {
    date +%s%N
}

function timer_start {
    timer_start=${timer_start:-$(timer_now)}
}

function timer_stop {
    local delta_us=$((($(timer_now) - $timer_start) / 1000))
    local us=$((delta_us % 1000))
    local ms=$(((delta_us / 1000) % 1000))
    local s=$(((delta_us / 1000000) % 60))
    local m=$(((delta_us / 60000000) % 60))
    local h=$((delta_us / 3600000000))
    # Goal: always show around 3 digits of accuracy
    if ((h > 0)); then timer_show=${h}h${m}m
    elif ((m > 0)); then timer_show=${m}m${s}s
    elif ((s >= 10)); then timer_show=${s}.$((ms / 100))s
    elif ((s > 0)); then timer_show=${s}.$(printf %03d $ms)s
    elif ((ms >= 100)); then timer_show=${ms}ms
    elif ((ms > 0)); then timer_show=${ms}.$((us / 100))ms
    else timer_show=${us}us
    fi
    unset timer_start
}


set_prompt () {
    Last_Command=$? # Must come first!
    Blue='\[\e[01;34m\]'
    White='\[\e[01;37m\]'
    Red='\[\e[01;31m\]'
    Green='\[\e[01;32m\]'
    Reset='\[\e[00m\]'
    FancyX='\342\234\227'
    Checkmark='\342\234\223'


    # Add a bright white exit status for the last command
    PS1="$White\$? "
    # If it was successful, print a green check mark. Otherwise, print
    # a red X.
    if [[ $Last_Command == 0 ]]; then
        PS1+="$Green$Checkmark "
    else
        PS1+="$Red$FancyX "
    fi

    # Add the ellapsed time and current date
    timer_stop
    PS1+="($timer_show) \t "

    # If root, just print the host in red. Otherwise, print the current user
    # and host in green.
    if [[ $EUID == 0 ]]; then
        PS1+="$Red\\u$Green@\\h "
    else
        PS1+="$Green\\u@\\h "
    fi
    # Print the working directory and prompt marker in blue, and reset
    # the text color to the default.
    PS1+="$Blue\\w \\\$$Reset "
}

trap 'timer_start' DEBUG
PROMPT_COMMAND='set_prompt'

Outra abordagem muito mínima é:

trap 'SECONDS=0' DEBUG
export PS1='your_normal_prompt_here ($SECONDS) # '

Isto mostra o número de segundos desde o último comando simples foi iniciado. O contador não é reposto se você simplesmente pressione Enter sem digitar um comando - que pode ser útil quando você quer apenas para ver quanto tempo o terminal foi para cima desde a última vez fez alguma coisa nele. Ele funciona muito bem para mim no Red Hat e Ubuntu. Não funcionou para mim sob Cygwin, mas não tenho certeza se isso é um bug ou apenas uma limitação de tentar executar Bash no Windows.

Uma possível desvantagem dessa abordagem é que você mantenha segundos Reposição, mas se você realmente precisa para preservar segundos, como o número de segundos desde chamada de shell inicial, você pode criar sua própria variável para o contador PS1 em vez de usar SEGUNDOS diretamente. Outra possível desvantagem é que uma grande segundos valor como "999999" pode ser ser melhor apresentado como dias + + + segundos horas minutos, mas é fácil de adicionar um filtro simples, tais como:

seconds2days() { # convert integer seconds to Ddays,HH:MM:SS
  printf "%ddays,%02d:%02d:%02d" $(((($1/60)/60)/24)) \
  $(((($1/60)/60)%24)) $((($1/60)%60)) $(($1%60)) |
  sed 's/^1days/1day/;s/^0days,\(00:\)*//;s/^0//' ; }
trap 'SECONDS=0' DEBUG
PS1='other_prompt_stuff_here ($(seconds2days $SECONDS)) # '

Isto traduz "999999" em "11 dias, 13: 46: 39". O sed no final muda "um dia" a "um dia", e as guarnições fora valores principais vazios, tais como "0 dias, 00:". Ajustar a gosto.

Se você não tinha criado qualquer das outras respostas antes que você começou o seu trabalho de longa duração e você só quer saber quanto tempo o trabalho levou, você pode fazer o simples

$ HISTTIMEFORMAT="%s " history 2

e ele irá responder com algo como

  654  1278611022 gvn up
  655  1278611714 HISTTIMEFORMAT="%s " history 2

e então você pode apenas visualmente subtrair os dois timestamps (conheço ninguém como capturar a saída do shell builtin comando história?)

Eu levei a resposta de Ville Laurikari e melhorou-lo usando o comando time para mostrar sub-segunda precisão:

function timer_now {
  date +%s%N
}

function timer_start {
  timer_start=${timer_start:-$(timer_now)}
}

function timer_stop {
  local delta_us=$((($(timer_now) - $timer_start) / 1000))
  local us=$((delta_us % 1000))
  local ms=$(((delta_us / 1000) % 1000))
  local s=$(((delta_us / 1000000) % 60))
  local m=$(((delta_us / 60000000) % 60))
  local h=$((delta_us / 3600000000))
  # Goal: always show around 3 digits of accuracy
  if ((h > 0)); then timer_show=${h}h${m}m
  elif ((m > 0)); then timer_show=${m}m${s}s
  elif ((s >= 10)); then timer_show=${s}.$((ms / 100))s
  elif ((s > 0)); then timer_show=${s}.$(printf %03d $ms)s
  elif ((ms >= 100)); then timer_show=${ms}ms
  elif ((ms > 0)); then timer_show=${ms}.$((us / 100))ms
  else timer_show=${us}us
  fi
  unset timer_start
}

trap 'timer_start' DEBUG
PROMPT_COMMAND=timer_stop

PS1='[last: ${timer_show}][\w]$ '

Claro que isso exige um processo a ser iniciado, por isso é menos eficiente, mas ainda rápido o suficiente para que você não iria aviso prévio.

Descobri que trap ... DEBUG estava correndo cada vez $PROMPT_COMMAND foi chamado, redefinindo o timer e, portanto, sempre retornando 0.

No entanto, descobri que os registros history vezes, e I aproveitado para estes para obter a minha resposta:

HISTTIMEFORMAT='%s '
PROMPT_COMMAND="
  START=\$(history 1 | cut -f5 -d' ');
  NOW=\$(date +%s);
  ELAPSED=\$[NOW-START];
  $PROMPT_COMMAND"
PS1="\$ELAPSED $PS1"

Não é perfeito, porém:

  • Se history não registra o comando (por exemplo repetida ou comandos ignorados), a hora de início será errado.
  • comandos Multi-linha não obter a data extraídos corretamente a partir history.

Outra abordagem para a festança 4.x e acima seria usar coproc com PS0 e PS1 como abaixo:

cmd_timer()
{
    echo $(( SECONDS - $(head -n1 <&"${CMD_TIMER[0]}") ))
}

coproc CMD_TIMER ( while read; do echo $SECONDS; done )
echo '' >&"${CMD_TIMER[1]}" # For value to be ready on first PS1 expansion
export PS0="\$(echo '' >&${CMD_TIMER[1]})"
export PS1="[ \$(cmd_timer) ] \$"

Este é um pronto trecho .bashrc. É especialmente útil para todos que usos undistract-me que sobrescreve trap DEBUG para seus próprios fins.

Will colocar um \ t no PS1 trabalho para você?

Ele não dá o tempo decorrido mas deve ser fácil o suficiente para subtrair os tempos quando necessário.

$ export PS1='[\t] [\w]\$ '
[14:22:30] [/bin]$ sleep 10
[14:22:42] [/bin]$

Após o comentário do OP que ele já está usando \ t. Se você pode usar tcsh em vez de bash, você pode definir a variável de tempo.

/bin 1 > set time = 0
/bin 2 > sleep 10
0.015u 0.046s 0:10.09 0.4%      0+0k 0+0io 2570pf+0w
/bin 3 >

Você pode alterar o formato da impressão de ser menos feia (se a página man tcsh).

/bin 4 > set time = ( 0 "last: %E" )
/bin 5 > sleep 10
last: 0:10.09
/bin 6 >

Eu não sei de uma instalação semelhante em bash

Esta é minha versão

  • data de uso ao tempo formato, apenas alguns dias calc
  • definir título do terminal
  • use \ $ em PS1 para o usuário $ + root #
  • código show de retorno / código de saída
  • data de uso u para desativar DST
  • usar nomes ocultos como _foo
_x_dt_min=1 # minimum running time to show delta T
function _x_before {
    _x_t1=${_x_t1:-$(date -u '+%s.%N')} # float seconds
}
function _x_after {
    _x_rc=$? # return code
    _x_dt=$(echo $(date -u '+%s.%N') $_x_t1 | awk '{printf "%f", $1 - $2}')
    unset _x_t1
    #_x_dt=$(echo $_x_dt | awk '{printf "%f", $1 + 86400 * 1001}') # test
    # only show dT for long-running commands
    # ${f%.*} = int(floor(f))
    (( ${_x_dt%.*} >= $_x_dt_min )) && {
        _x_dt_d=$((${_x_dt%.*} / 86400))
        _x_dt_s='' # init delta T string
        (( $_x_dt_d > 0 )) && \
            _x_dt_s="${_x_dt_s}${_x_dt_d} days + "
        # format time
        # %4N = four digits of nsec
        _x_dt_s="${_x_dt_s}$(date -u -d0+${_x_dt}sec '+%T.%4N')"
        PS1='rc = ${_x_rc}\ndT = ${_x_dt_s}\n\$ '
    } || {
        PS1='rc = ${_x_rc}\n\$ '
    }
    # set terminal title to terminal number
    printf "\033]0;%s\007" $(tty | sed 's|^/dev/\(pts/\)\?||')
}
trap '_x_before' DEBUG
PROMPT_COMMAND='_x_after'
PS1='\$ '

saída da amostra:

$ sleep 0.5
rc = 0
$ sleep 1
rc = 0
dT = 00:00:01.0040
$ sleep 1001d
rc = 0
dT = 1001 days + 00:00:00.0713
$ false
rc = 1
$ 

Aqui está minha opinião sobre Thomas'

usos date +%s%3N para obter milissegundos como unidade de base, código a seguir simplificado (menos zeros)

function t_now {
    date +%s%3N
}

function t_start {
    t_start=${t_start:-$(t_now)}
}

function t_stop {
    local d_ms=$(($(t_now) - $t_start))
    local d_s=$((d_ms / 1000))
    local ms=$((d_ms % 1000))
    local s=$((d_s % 60))
    local m=$(((d_s / 60) % 60))
    local h=$((d_s / 3600))
    if ((h > 0)); then t_show=${h}h${m}m
    elif ((m > 0)); then t_show=${m}m${s}s
    elif ((s >= 10)); then t_show=${s}.$((ms / 100))s
    elif ((s > 0)); then t_show=${s}.$((ms / 10))s
    else t_show=${ms}ms
    fi
    unset t_start
}
set_prompt () {
t_stop
}

trap 't_start' DEBUG
PROMPT_COMMAND='set_prompt' 

Em seguida, adicione $t_show ao seu PS1

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top