A customizable application launcher that extends the functionality of dmenu_run
by allowing custom commands, dynamic script outputs, and alias support. Perfect for i3 window manager users who want more than just application launching.
- Custom Commands: Add frequently used commands without modifying system-wide configurations
- Dynamic Scripts: Integration of scripts that generate entries on demand
- Alias Support: Define and use aliases in your command list
- Cross-Platform: Seamless support for both X11 (dmenu) and Wayland (bemenu)
- FZF Integration: Provides FZF environment variable for nested fuzzy finding
- Extensible: Easy to extend with your own scripts and commands
dmenu
(for X11) orbemenu
(for Wayland)- Shell environment (bash, zsh, etc.)
- Save the script as
dmenu_run2
- Make it executable:
chmod +x dmenu_run2
- Place it in your PATH or use the full path in your window manager config
DMENU_RUN_COMMANDS
: Path to a file containing custom commands (one per line)DMENU_RUN_BIN
: Path to a directory containing executable scripts that output commandsDMENU
: Override the default dmenu command (default:dmenu
,bemenu
on Wayland)DMENU_NO_PATH
: Set to "true" to exclude system PATH applicationsFZF
: Automatically set to current dmenu command for nested script usage
# In your shell profile or window manager config
export DMENU_RUN_COMMANDS="$HOME/.config/dmenu/commands"
export DMENU_RUN_BIN="$HOME/.config/dmenu/scripts"
# Simple launch
./dmenu_run2
# With dmenu options
./dmenu_run2 -p 'Run:' -i -l 10
Add to your i3 config (~/.config/i3/config
):
bindsym $mod+d exec DMENU_RUN_BIN="$HOME/.config/dmenu/scripts" DMENU_RUN_COMMANDS="$HOME/.config/dmenu/commands" /path/to/dmenu_run2 -p 'Run:'
Create a file at $DMENU_RUN_COMMANDS
with your frequently used commands:
# Network commands
nmcli radio wifi on
nmcli radio wifi off
systemctl suspend
systemctl poweroff
# Aliases
alias wifi on="nmcli radio wifi on"
alias wifi off="nmcli radio wifi off"
alias suspend="systemctl suspend"
Extracting aliases is very simplExtracting aliases is very simple, it starts with the alias
keyword followed by the alias name, followed by the equal sign =
and the command. You can also include arguments and spaces in the alias name and the command.
alias name=command --with-args
alias name with spaces=command2
The script will extract the alias name for display and resolve to the actual command when selected.
Check the examples/scripts directory for additional example scripts:
- examples/scripts/network: NetworkManager connection management
- examples/scripts/bluetooth: Bluetooth device control
- examples/scripts/tmux: Tmux script loader
All scripts in the repository are ready to use - just copy them to your $DMENU_RUN_BIN
directory and make them executable.
Scripts executed through dmenu_run2 can use the FZF
environment variable to maintain consistency:
#!/bin/sh
# File: ~/.config/dmenu/scripts/dictionary
fuzzy_find="${FZF:-fzf}"
$fuzzy_find < /usr/share/dict/words
When called from dmenu_run2, this will use dmenu. When called directly, it falls back to fzf. That way, you can use the same script in different contexts without modification.
Override the default dmenu command:
export DMENU="rofi -dmenu -i -no-fixed-num-lines -no-show-icons"
To only show custom commands and scripts:
export DMENU_NO_PATH="true"
- Create directories:
mkdir -p ~/.config/dmenu/scripts
- Create commands file
~/.config/dmenu/commands
:
# System controls
systemctl suspend
systemctl poweroff
systemctl reboot
# Network
nmcli radio wifi on
nmcli radio wifi off
# Aliases
alias lock="i3lock -c 000000"
alias screenshot="scrot ~/Pictures/screenshot_%Y%m%d_%H%M%S.png"
- Create a network script ~/.config/dmenu/scripts/network:
#!/bin/sh
nmcli -f active,name connection show | awk 'BEGIN { FS=" +" } NR > 1 {
if ($1 == "no") {
printf("alias %s up=nmcli connection up \"%s\"\n", $2, $2)
} else {
printf("alias %s down=nmcli connection down \"%s\"\n", $2, $2)
}
}'
```bash
chmod +x ~/.config/dmenu/scripts/network
- Add to i3 config:
bindsym $mod+d exec DMENU_RUN_BIN="$HOME/.config/dmenu/scripts" DMENU_RUN_COMMANDS="$HOME/.config/dmenu/commands" dmenu_run2 -p 'Run:'
Ensure scripts in DMENU_RUN_BIN
are executable:
chmod +x ~/.config/dmenu/scripts/*
Check that your files exist and are readable:
ls -la "$DMENU_RUN_COMMANDS"
ls -la "$DMENU_RUN_BIN"
The script automatically detects Wayland and uses bemenu
. Install it if needed:
# Ubuntu/Debian
sudo apt install bemenu
# Arch Linux
sudo pacman -S bemenu
The repository also includes dmenu_script
, a utility that creates interactive command pipelines where each dmenu selection becomes input for the next command execution.
The script creates a loop where:
- An executable script generates options
- User selects an option via dmenu
- The selection becomes input to the script for the next iteration
- Process continues until empty selection or command completion
./dmenu_script <executable_file> <dmenu_options>
Create an interactive script that responds to selections ~/.config/dmenu/scripts/interactive_example:
#!/usr/bin/env sh
case "$1" in
"")
# Initial menu
printf 'System\nNetwork\nApplications'
;;
"System")
printf 'Lock Screen\nSuspend\nReboot\nShutdown'
;;
"Network")
printf 'WiFi On\nWiFi Off\nConnections'
;;
"Applications")
printf 'Firefox\nTerminal\nText Editor'
;;
"Lock Screen")
i3lock -c 000000
exit 0
;;
"Suspend")
systemctl suspend
exit 0
;;
"WiFi On")
nmcli radio wifi on
exit 0
;;
"Firefox")
firefox &
exit 0
;;
*)
echo "Unknown option: $1" >&2
exit 1
;;
esac
chmod +x ~/.config/dmenu/scripts/interactive_example
# Basic usage
./dmenu_script ~/.config/dmenu/scripts/interactive_example
# With dmenu options
./dmenu_script ~/.config/dmenu/scripts/interactive_example -p "Select:" -l 10
# i3 binding
bindsym $mod+i exec /path/to/dmenu_script ~/.config/dmenu/scripts/interactive_example -p "Menu:"
Interactive scripts should:
- Accept an optional argument (
$1
) - Output selectable options (one per line)
- Handle the empty case (
""
) for initial menu - Exit with status 0 when a final action is performed
- Exit with non-zero status on errors
Here's a system monitor that demonstrates the interactive pipeline concept ~/.config/dmenu/scripts/system_monitor:
#!/usr/bin/env sh
case "$1" in
""|"Back to main menu")
# Main menu
echo "CPU Usage"
echo "Memory Usage"
echo "Disk Usage"
echo "Network"
echo "Processes"
echo "Quit"
;;
"CPU Usage")
# Show CPU info and options
top -bn1 | grep "Cpu(s)" | awk '{print $2}' | sed 's/%us,/% CPU usage/'
echo "Show top CPU processes"
echo "Back to main menu"
echo "Quit"
;;
"Memory Usage")
# Show memory info and options
free -h | grep "Mem:" | awk '{printf "Memory: %s used / %s total\n", $3, $2}'
echo "Show memory-heavy processes"
echo "Back to main menu"
echo "Quit"
;;
"Disk Usage")
# Show disk usage
df -h / | tail -1 | awk '{printf "Root: %s used / %s total (%s)\n", $3, $2, $5}'
echo "Back to main menu"
echo "Quit"
;;
"Network")
# Show network info
echo "Active connections:"
ss -tuln | wc -l | awk '{printf "%d active connections\n", $1-1}'
echo "Show network connections"
echo "Back to main menu"
echo "Quit"
;;
"Show top CPU processes")
ps aux --sort=-%cpu | head -6 | tail -5 | awk '{printf "%s: %.1f%%\n", $11, $3}'
echo "Back to main menu"
echo "Quit"
;;
"Show memory-heavy processes")
ps aux --sort=-%mem | head -6 | tail -5 | awk '{printf "%s: %.1f%%\n", $11, $4}'
echo "Back to main menu"
;;
"Quit")
exit 0
;;
*)
echo "Unknown option: $1" >&2
exit 1
;;
esac
chmod +x ~/.config/dmenu/scripts/system_monitor
This example shows practical navigation:
- First run: Shows main system categories
- User selects:
Memory Usage
- Second run: Shows current memory usage + options to drill down
- User selects:
Show memory-heavy processes
- Third run: Shows top memory-consuming processes + actions
Each selection navigates deeper into system information while maintaining context.
MIT License - See the script header for full license text.