Ответ 1
Вы можете использовать этот зацепленный zsh хук для bash: http://www.twistedmatrix.com/users/glyph/preexec.bash.txt
Временные рамки выполняются с помощью этого хука (Mac OS X): используйте Growl для мониторинга длительных команд оболочки
Есть ли способ вставить последнюю команду, прошедшую время стены, в подсказку Bash? Я надеюсь на то, что будет выглядеть так:
[last: 0s][/my/dir]$ sleep 10
[last: 10s][/my/dir]$
Фон
Я часто запускаю длинные задания хрустания данных, и полезно знать, сколько времени они взяли, поэтому я могу оценить, сколько времени это займет для будущих работ. Для очень регулярных задач я продолжаю и фиксирую эту информацию строго с использованием соответствующих методов ведения журнала. Для менее формальных задач я просто добавлю команду с помощью time
.
Было бы удобно автоматически time
каждую отдельную интерактивную команду и иметь информацию о времени, напечатанную несколькими символами, а не 3 строками.
Вы можете использовать этот зацепленный zsh хук для bash: http://www.twistedmatrix.com/users/glyph/preexec.bash.txt
Временные рамки выполняются с помощью этого хука (Mac OS X): используйте Growl для мониторинга длительных команд оболочки
Это минимальный автономный код для достижения того, что вы хотите:
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]$ '
Используя ваши ответы и некоторые другие темы, я написал это приглашение, которое хочу поделиться с вами. Я сделал скриншот, в котором вы можете увидеть:
Вот код, который нужно поместить в файл ~/.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\\[email protected]\\h "
else
PS1+="$Green\\[email protected]\\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'
Другой очень минимальный подход:
trap 'SECONDS=0' DEBUG
export PS1='your_normal_prompt_here ($SECONDS) # '
Показывает количество секунд с момента запуска последней простой команды. Счетчик не reset, если вы просто нажмете Enter без ввода команды - что может быть удобно, когда вы просто хотите узнать, сколько времени прошло с тех пор, как вы в последний раз что-то делали в нем. Он отлично работает для меня в Red Hat и Ubuntu. Это НЕ работало для меня под Cygwin, но я не уверен, что это ошибка или просто ограничение на запуск Bash под Windows.
Один из возможных недостатков этого подхода заключается в том, что вы продолжаете сбросить SECONDS, но если вам действительно нужно сохранить SECONDS в качестве количества секунд с момента вызова оболочки, вы можете создать свою собственную переменную для счетчика PS1, а не напрямую использовать SECONDS. Другим возможным недостатком является то, что значительная секундная величина, такая как "999999", может быть лучше показана как дни + часы + минуты + секунды, но легко добавить простой фильтр, например:
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)) # '
Это переводит "999999" в "11days, 13: 46: 39". Сед в конце меняет "1days" на "1day" и отбрасывает пустые начальные значения, такие как "0days, 00:". Отрегулируйте вкус.
Если вы не настроили какие-либо другие ответы перед тем, как начать свою долговременную работу, и вам просто нужно знать, как долго работа была выполнена, вы можете сделать простой
$ HISTTIMEFORMAT="%s " history 2
и он ответит чем-то вроде
654 1278611022 gvn up
655 1278611714 HISTTIMEFORMAT="%s " history 2
и тогда вы можете просто визуально вычесть две временные метки (кто-нибудь знает, как захватить вывод команды history builtin history?)
Я взял ответ от Ville Laurikari и улучшил его с помощью команды time
, чтобы показать точность секунды:
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]$ '
Конечно, для этого требуется запуск процесса, поэтому он менее эффективен, но все же достаточно быстр, чтобы вы не заметили.
Я обнаружил, что trap ... DEBUG
запускался каждый раз, когда вызывался $PROMPT_COMMAND
, сброс таймера и поэтому всегда возвращал 0.
Однако я обнаружил, что history
записывает времена, и я использовал их для получения ответа:
HISTTIMEFORMAT='%s '
PROMPT_COMMAND="
START=\$(history 1 | cut -f5 -d' ');
NOW=\$(date +%s);
ELAPSED=\$[NOW-START];
$PROMPT_COMMAND"
PS1="\$ELAPSED $PS1"
Это не идеально, хотя:
history
не регистрирует команду (например, повторяющиеся или проигнорированные команды), время начала будет неправильным.history
. Другим подходом для bash 4.x и выше будет использование coproc
с PS0
и PS1
как PS0
ниже:
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) ] \$"
Это готовый фрагмент .bashrc
. Это особенно полезно для всех, кто использует утилиту unistract-me, которая перезаписывает trap DEBUG
для своих собственных целей.
Работает ли \t в PS1 для вас?
Это не дает прошедшее время, но должно быть достаточно легко вычесть время, когда это необходимо.
$ export PS1='[\t] [\w]\$ '
[14:22:30] [/bin]$ sleep 10
[14:22:42] [/bin]$
Следуя комментарию OP, он уже использует \t. Если вы можете использовать tcsh вместо bash, вы можете установить временную переменную.
/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 >
Вы можете изменить формат печати менее уродливым (см. справочную страницу tcsh).
/bin 4 > set time = ( 0 "last: %E" )
/bin 5 > sleep 10
last: 0:10.09
/bin 6 >
Я не знаю подобного объекта в bash
это моя версия
_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='\$ '
образец вывода:
$ 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
$
Вот мой взгляд на Томаса
использует date +%s%3N
для получения миллисекунд в качестве базовой единицы, упрощенный следующий код (меньше нулей)
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'
Затем добавьте $t_show
к вашей PS1