Sound when bash command is ending
bash, command-line, notifications, shell
Solution
I had the same question and thanks to @rici's answer I was able to come up with a working solution. You can join PROMPT_COMMAND into a single line if you want, or leave it like this:
trap '_T=${_T:-$SECONDS}' DEBUG
PROMPT_COMMAND='
((SECONDS - _T > 10)) &&
{ play ~/done.wav &disown;}&>/dev/null;
unset _T
'
This combination of settings will play `~/done.wav` whenever a command-line takes more than 10 seconds to complete. It will not play the sound just by leaving your terminal idle.
On OS X the command to play a sound is `afplay` and a few sounds can be found in `/System/Library/Sounds`
But the version above cannot tell between long-running batch commands, for which we want a sound, and interactive ones, such as your choice of terminal editor, man pages, `|less`, and such.
Here's a version that does tell, 99% of the time, by checking the last commandline against a regexp with one's list of common interactive programs or pipes:
trap '_T=${_T:-$SECONDS}' DEBUG
PROMPT_COMMAND='
if ((SECONDS - _T > 10)); then
l=$(history 1);
[[ ! ${l:7} =~ (^vim|^man|^ssh|less$) ]] &&
{ play ~/done.wav &disown;}&>/dev/null;
fi;
unset _T
'
You should adjust the regexp to taste. Again, you can join PROMPT_COMMAND into a single line if you want, I've left the `;` where they should be on a single-liner.
This is still efficient, because:
- the shell doesn't spawn any external process while evaluating either hook (except for the obvious sound playing, which is launched in the background);
- the DEBUG hook is very fast; I believe it doesn't even access the "magic variable" $SECONDS (which probably forces a syscall to get the current time) more than twice per command-line, in the first DEBUG and in PROMPT_COMMAND to compare the values;
- the history check and regexp is only done if the command took more than N seconds.
How it works
To understand how it works, you can set these debug prints:
trap 'echo DEBUG' DEBUG
PROMPT_COMMAND='echo PROMPT_COMMAND'
and then pay attention to when they are called:
PROMPT_COMMAND
$ sleep 2; sleep 2
DEBUG
(1st sleep takes its time)
DEBUG
(2nd sleep takes its time)
DEBUG
PROMPT_COMMAND
$ (user waits before pressing enter)
DEBUG
PROMPT_COMMAND
$
In light of this, my settings above:
- unset _T whenever a prompt is shown to the user—at the end of `$PROMPT_COMMAND`;
- if _T is unset, which happens in the first `DEBUG` of every command-line, right after you press enter; then set it to the current time (using `$SECONDS` which is more efficient than launching an external `date` process);
- at the next prompt, compare _T with the current time and play the sound if needed, launching the play command in the background and discarding any output (including `[1] PID` and other job-related info.)
Problem
When I start a long command in bash I need for signal sounded at its command completion. How it to make in .bashrc for all long command? I have alsa for sounds. Search in google without results.