Skip to content

Instantly share code, notes, and snippets.

@quinncomendant
Created March 21, 2025 03:16
Show Gist options
  • Save quinncomendant/4778d829fc5e9258850c6d258beca2ac to your computer and use it in GitHub Desktop.
Save quinncomendant/4778d829fc5e9258850c6d258beca2ac to your computer and use it in GitHub Desktop.
A bash script to raise a macOS notification or alert with no dependencies. Save this file as `notify` and then symlink it to `alert`.
#!/usr/bin/env bash
#
# Quinn Comendant <[email protected]>
# 11 Jul 2020 11:18:13
set -o pipefail;
set -o errexit;
set -o nounset;
set -o noclobber;
scriptname=$(basename "$0");
#
# Functions
#
function _usage() {
echo "Usage: $scriptname [OPTIONS] [< STDIN]
Raise a macOS notification using AppleScript.
OPTIONS
-m MESSAGE The notification message (required if not using STDIN).
-s SUBTITLE A notification subtitle.
-S Play a notification sound.
-t TITLE A notification title.
";
exit 1;
}
function _error() {
local IFS='';
echo -e "$*" 1>&2
exit 1;
}
function _notify() {
export notify_message notify_subtitle notify_title notify_sound;
if [[ -n $notify_sound ]]; then
osascript -e 'display notification (system attribute "notify_message") with title (system attribute "notify_title") subtitle (system attribute "notify_subtitle") sound name (system attribute "notify_sound")' >/dev/null &
# osascript -e 'tell application "Finder"' -e 'activate' -e 'display notification (system attribute "notify_message") with title (system attribute "notify_title") subtitle (system attribute "notify_subtitle") sound name (system attribute "notify_sound")' -e 'end tell' &
else
osascript -e 'display notification (system attribute "notify_message") with title (system attribute "notify_title") subtitle (system attribute "notify_subtitle")' >/dev/null &
# osascript -e 'tell application "Finder"' -e 'activate' -e 'display notification (system attribute "notify_message") with title (system attribute "notify_title") subtitle (system attribute "notify_subtitle")' -e 'end tell' &
fi
}
function _alert() {
if [[ -n $notify_subtitle ]]; then
notify_title="${notify_title} (${notify_subtitle})";
fi
export notify_message notify_title notify_sound;
osascript -e 'display alert (system attribute "notify_title") message (system attribute "notify_message") as critical buttons {"OK"} default button "OK"' >/dev/null &
# osascript -e 'tell application "Finder"' -e 'activate' -e 'display alert (system attribute "notify_title") message (system attribute "notify_message") as critical buttons {"OK"} default button "OK"' -e 'end tell' >/dev/null &
if [[ -n $notify_sound ]]; then
sleep 1 && afplay /System/Library/Sounds/Pop.aiff &>/dev/null &
fi
}
function _iconv() {
local str;
read -rd '' str;
iconv -f UTF8 -t MACROMAN//IGNORE <<<"$str" 2>/dev/null || true;
}
#
# Main
#
# Look at stdin for the message (`-t 0` tests if input is not a tty, i.e., stdin exists via pipe).
notify_message=;
if [[ ! -t 0 ]]; then
notify_message=$(_iconv);
fi
# Display help if run without arguments.
[[ $# == 0 && -z $notify_message ]] && _usage 1>&2
# Process command line options.
notify_subtitle='';
notify_title='Terminal';
notify_sound='';
while getopts 'hm:s:St:-:' opt ; do
case $opt in
(h) _usage;;
(m) if [[ -n $notify_message ]]; then
_error "Message provided via -m and stdin; choose one and try again.";
fi
notify_message=$(_iconv <<<"$OPTARG");;
(t) notify_title=$(_iconv <<<"$OPTARG");;
(s) notify_subtitle=$(_iconv <<<"$OPTARG");;
(S) notify_sound='Pop';;
(-) case $OPTARG in
(help) _usage;;
(?) _error "Invalid option: '$OPTARG'. Run with -h for help.";;
esac ;;
(?) _error "Invalid option: '$opt'. Run with -h for help.";;
(*) _error "An unexpected error occurred.";;
esac
done
# Remove options.
shift $((OPTIND - 1))
[[ -z $notify_message ]] && _error "No message provided. Run with -h for help.";
type -P osascript >/dev/null || _error "The osascript command is not available";
case $scriptname in
(notify) _notify;;
(alert) _alert;;
esac
unset -v notify_message notify_subtitle notify_title notify_sound;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment