I use command-line a lot and sometimes a command takes time to execute. So, months ago, I started to use the following alias:
alias beeps='for i in {1..5}; do aplay -q /usr/share/sounds/generic.wav; sleep 0.5s; done'
I ran it like:
command ; beeps
I just left the command to run and came back when I heard the beeping sound. That alias was just ugly simple and did what I need: getting notified when the job is done. It's very help for running commands don't have notifications, which most command-line program wouldn't have. I just append the beeps after the commands, such as eix-sync, emerge, etc.

I updated the alias, so it would play different sounds depending on the exit status, also it retains the exit status after it plays the sound. Although, I don't think retain of exit status is really necessary, nonetheless it's not hard to implement and nice to have.
alias beeps='(BEEPS_RET=$? ; ((BEEPS_RET)) && BEEPS=error || BEEPS=generic ; for i in {1..5} ; do (aplay -q /usr/share/sounds/$BEEPS.wav &) >/dev/null ; sleep 1 ; done ; exit $BEEPS_RET)'
With pretty-print:
(
  BEEPS_RET=$?
  ((BEEPS_RET)) && BEEPS=error || BEEPS=generic
  for i in {1..5}; do
    (aplay -q /usr/share/sounds/$BEEPS.wav &) >/dev/null
    sleep 1
  done
  exit $BEEPS_RET
)
I use sub-shell to so the variables don't contaminate the current shell. This may look better by using function, but I started with alias, so continued with alias. If you wants to use function, just replace sub-shell with function, declare the variables are local, replace exit with return.