Several times, i launched heavy computations from a bash terminal, and then worked on something else waiting for them to finish. And then 3 hours later, discover that they failed at the first minute.
Sometimes it’s the opposite : i wait for them to finish, but… they already finished.
Solution : Make bash play a sound when a heavy command succeeds or fails !
1) Play a sound from the terminal
We will use the program aplay.
$ aplay -q ~/Public/my_sound.wav
So, i downloaded some free scores in wav format and edited them to cut and extract just a piece of Haendel’s Hallelujah (for successful jobs) and Chopin’s Funeral March (for failed jobs).
$ aplay -q ~/Public/hallelujah.wav
$ aplay -q ~/Public/funeral.wav
2) Get the return code of a command
Bash has a variable « ? » that stores the return code of the last executed command. After running something, you can try:
$ echo $?
0
If it returns 0, it means that everything went well (no errors). Otherwise, the value is supposed to help you to understand what the problem was using the command’s documentation (it is often -1, 1, 2 …).
So we can store this value and then test it to play the right sound. (We need to store it, because our bash code will also modify the « ? » variable).
LAST=$?;
if [ $LAST -eq 0 ];
then aplay -q ~/Public/hallelujah.wav;
else aplay -q ~/Public/funebre.wav;
fi;
3) Set it permanently
We need to add the previous code to the $PROMPT_COMMAND variable, which contains the instructions executed after a command to restore a command prompt (like displaying $PS1, etc…).
PROMPT_COMMAND='LAST=$?; if [ $LAST -eq 0 ]; then aplay -q ~/Public/hallelujah.wav; else aplay -q ~/Public/funebre.wav; fi'
To get a permanent effect everytime you open a terminal, edit your .bashrc file (nano ~/.bashrc) and add the line at the end.
Note that on some terminals, the PROMPT_COMMAND is overwritten by /etc/profile.d/vte.sh. I partially solved the problem by editing /etc/profile.d/vte.sh and commenting the line that sets PROMPT_COMMAND.
4) Restrict it to very-long command only
As it is annoying to play 15 seconds of sound at every cd and ls, we need to restrict the execution to long commands.
To measure the running time of a command we need to compute the difference between the time when it started and the time when it exited.
We get the current time this way (number of seconds since January the first 1970):
$ printf "%(%s)T" -1
1557489306
We can store the result of printf into a variable with printf -v:
printf -v __timer_start "%(%s)T" -1
printf -v __timer_stop "%(%s)T" -1
We already know how to execute it at the end of a command, it’s using PROMPT_COMMAND. We will add the second line into it.
To execute a command when another command starts, we will use the trap DEBUG linux command:
$ trap 'something to execute' DEBUG
We can use it to execute something at the begining of every command.
Then, we will store the difference between __timer_start and __timer_stop into a variable __timer (using printf -v again), which we will test to know if we should play a sound or not (example : if [ $__timer -gt 10 ] for ten seconds threshold).
5) All together
Modify your .bashrc to include the two following lines (the trap, and the PROMPT_COMMAND definition):
trap '[ -v __timer_start ] || TZ=UTC printf -v __timer_start "%(%s)T" -1' DEBUG
PROMPT_COMMAND='LAST=$?; TZ=UTC printf -v __timer_stop "%(%s)T" -1; TZ=UTC printf -v __timer $((__timer_stop - __timer_start)); if [ $__timer -gt 10 ]; then if [ $LAST -eq 0 ]; then aplay -q ~/Public/hallelujah.wav; else aplay -q ~/Public/funeral.wav; fi; fi; unset __timer_start'
To make it work, you need to unset the $__timer_start variable at the very end.
The TZ=UTC are only used to define the time-zone (not so useful).
Here it is !
Open a terminal.
persalteas@persalstation[~]$ ls
Data labo logo_univ.png Modèles Release.key signature.png Téléchargements Bureau Documents Libraries mcfold.htm Projects Public Seafile Software Zotero
persalteas@persalstation[~]$ sleep 11
persalteas@persalstation[~]$ sleep 11; ls aiefv
ls: impossible d'accéder à 'aiefv': Aucun fichier ou dossier de ce type
The first command (ls) plays nothing. The second (sleep 11) takes 11 seconds and plays Hallelujah. The last (sleep 11; ls aiefv) takes 11 seconds, fails, and plays the Funeral March.
Enjoy !