Skip to content

Instantly share code, notes, and snippets.

@Ajnasz
Last active July 8, 2025 05:33
Show Gist options
  • Save Ajnasz/4f1586775d4c6edd3666fc376d4b3296 to your computer and use it in GitHub Desktop.
Save Ajnasz/4f1586775d4c6edd3666fc376d4b3296 to your computer and use it in GitHub Desktop.
#!/usr/bin/env sh
# This script extends the functionality of dmenu_run by allowing the user to
# include custom commands and executables. The custom commands are read from a
# file specified by the environment variable DMENU_RUN_COMMANDS, and the
# executables are read from a directory specified by the environment variable
# DMENU_RUN_BIN.
#
# Environment Variables:
# DMENU_RUN_COMMANDS: Path to a file containing custom commands to be included
# in the dmenu. The file should contain one command per line.
# Each line can be a regular command or an alias defined in the
# format:
# alias name="command --with-args"
# alias name="command2"
#
# DMENU_RUN_BIN: Path to a directory containing executables.
# The executables should echo the commands to be included in
# the dmenu.
#
# Usage:
# Set the environment variables DMENU_RUN_COMMANDS and DMENU_RUN_BIN to point
# to your custom commands file and executables directory, respectively. Then,
# run the script. The script will add the custom commands and executables to
# the dmenu.
#
# Example:
# DMENU_RUN_COMMANDS=/path/to/commands.txt DMENU_RUN_BIN=/path/to/bin \
# ./dmenu_run2
#
# Note:
# The script assumes that all files in the DMENU_RUN_BIN directory are
# executable and that they will echo the correct commands. Ensure that these
# conditions are met to avoid unexpected behavior.
#
# The script runs in the background, and the selected command from the dmenu
# is executed in a subshell.
# Function to extract alias name from alias definition
# shellcheck disable=SC2317 # Don't warn about unreachable commands in this function
extract_alias_name() {
printf '%s\n' "$1" | sed 's/^alias \([^=]*\)=.*/\1/'
}
# Function to extract alias command from alias definition
# shellcheck disable=SC2317 # Don't warn about unreachable commands in this function
extract_alias_command() {
printf '%s\n' "$1" | sed 's/^alias [^=]*=//' | sed 's/^"\(.*\)"$/\1/'
}
# Function to process custom commands and aliases
# shellcheck disable=SC2317 # Don't warn about unreachable commands in this function
process_custom_commands() {
if [ -n "$DMENU_RUN_COMMANDS" ] && [ -f "$DMENU_RUN_COMMANDS" ]; then
while IFS= read -r line || [ -n "$line" ]; do
# Skip comments and empty lines
case "$line" in
\#*|'') continue ;;
alias\ *=*)
# Extract and display alias name only
extract_alias_name "$line"
;;
*)
# Regular command
printf '%s\n' "$line"
;;
esac
done < "$DMENU_RUN_COMMANDS"
fi
}
# Function to resolve alias to its command
# shellcheck disable=SC2317 # Don't warn about unreachable commands in this function
resolve_alias() {
if [ -z "$DMENU_RUN_COMMANDS" ] || [ ! -f "$DMENU_RUN_COMMANDS" ]; then
# echo the stdin input to stdout
while IFS= read -r selected || [ -n "$selected" ]; do
printf '%s\n' "$selected"
done
return 0
fi
while IFS= read -r selected || [ -n "$selected" ]; do
# read $DMENU_RUN_COMMANDS and resolve aliases
while IFS= read -r line || [ -n "$line" ]; do
case "$line" in
alias\ *=*)
alias_name=$(extract_alias_name "$line")
if [ "$selected" = "$alias_name" ]; then
alias_command=$(extract_alias_command "$line")
# If selected item is an alias, print its command
printf '%s\n' "$alias_command"
return 0
fi
;;
*)
# If selected item is a regular command, print it as is
if [ "$selected" = "$line" ]; then
printf '%s\n' "$line"
return 0
fi
;;
esac
done < "$DMENU_RUN_COMMANDS"
printf '%s\n' "$selected"
done
}
if [ -z "$DMENU_RUN_BIN" ] || [ ! -d "$DMENU_RUN_BIN" ];then
echo "DMENU_RUN_BIN is not set or is not a directory" >&2
fi
if [ -z "$DMENU_RUN_COMMANDS" ] || [ ! -f "$DMENU_RUN_COMMANDS" ];then
echo "DMENU_RUN_COMMANDS is not set or is not a file" >&2
fi
DMENU="dmenu"
# DMENU="rofi -dmenu -i -no-fixed-num-lines -no-show-icons"
if [ -n "$WAYLAND_DISPLAY" ]; then
DMENU="bemenu"
fi
{
# include output of executables from DMENU_RUN_BIN
if [ -n "$DMENU_RUN_BIN" ] && [ -d "$DMENU_RUN_BIN" ]; then
find "$DMENU_RUN_BIN" -maxdepth 1 -type f -executable -exec {} \;
fi
# include custom commands from DMENU_RUN_COMMANDS
if [ -n "$DMENU_RUN_COMMANDS" ] && [ -f "$DMENU_RUN_COMMANDS" ]; then
process_custom_commands < "$DMENU_RUN_COMMANDS"
fi
# always include dmenu_path
if [ "$DMENU_NO_PATH" != "true" ]; then
dmenu_path;
fi
} | $DMENU "$@" | resolve_alias | env FZF="$DMENU $*" "${SHELL:-"/usr/bin/env sh"}" &
exit 0;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment