How to create and use custom dmenu scripts

Dmenu is a dynamic menu for X often used on minimal window managers setups. It is part of the suckless tools suite of free and open source utilities created by the suckless.org project, which include, among the others, the dwm window manager and the st terminal emulator.

In this tutorial we see how to install dmenu on the most used Linux distributions, and how to create custom dmenu scripts.

In this tutorial you will learn:

  • How to install dmenu on the most used Linux distributions
  • How to create custom dmenu scripts
How to create custom dmenu scripts
How to create custom dmenu scripts – Original image by freepik
 
Software Requirements and Linux Command Line Conventions
Category Requirements, Conventions or Software Version Used
System Distribution-agnostic
Software dmenu
Other None
Conventions # – requires given linux-commands to be executed with root privileges either directly as a root user or by use of sudo command
$ – requires given linux-commands to be executed as a regular non-privileged user

Installation

Since all the major Linux distributions include dmenu in their official repositories, installing it is really easy. In the table below, you can see the exact command we can use on Fedora, Debian and Archlinux systems:

Fedora $ sudo dnf install dmenu
Debian $ sudo apt install suckless-tools
Archlinux $ sudo pacman -S dmenu

Notice that on Debian, the utility is provided by the “suckless-tools” package, which includes other utilities such as “lsw” and “slock”.

Using dmenu to launch applications

Dmenu is typically used to launch applications. To invoke the menu from the command line, we can use the dmenu_run script. More realistically, however, we want to associate the script to a keyboard shortcut. How to do it depends on the desktop environment or window manager we are working on.



When we invoke dmenu_run, all binaries in our PATH are displayed in dmenu, so we can select the one we want to launch:

dmenu

The list is filtered as we type:

dmenu search filter

Dmenu, by default, displays entries horizontally. We can, however, produce a vertical list by using the -l option, passing the maximum number of lines which should be displayed at a time as argument. The options and arguments we pass to the dmenu_run script are forwarded to dmenu itself, so, supposing we want to produce a list of maximum 10 lines at a time, we would write:

$ dmenu_run -l 10

Here is the result of running the command:

Vertical dmenu
Vertical dmenu

There are many ways we can customize the look and feel of dmenu. We can, for example, create a custom prompt by using the -p option, passing the text we want to be displayed as argument. Here is an example:

$ dmenu_run -l 10 -p "Choose application:"

The command above produces the following dmenu:

Dmenu custom prompt
Dmenu custom prompt

How dmenu works

To write our custom dmenu scripts, we must first understand how dmenu works under the hood. Dmenu reads and displays a newline separated list of items from the standard input. When the user selects an item from the list, by pressing the Return key, the choice is printed on the application standard output.

To see a practical example of how to use dmenu, we can take a look at the content of the dmenu_run script:

#!/bin/sh 
dmenu_path | dmenu "$@" | ${SHELL:-"/bin/sh"} &

We can see how dmenu_run basically invokes another script, dmenu_path, which returns a list of the executables in our PATH as output. A shell pipe is used to pass the output as input to dmenu, which is invoked with the same arguments of dmenu_run (the $@ shell variable expands to the positional parameters passed to a script).



The application list is displayed in dmenu. As we said, when we select an entry, our choice is printed on the standard output. In this case this output is piped to a shell, and is executed in the background, due to the & symbol being used.

Now that we understood how simply and powerful dmenu is, and how it works, we can create our custom scripts. Here we show some examples.

A custom script example: selecting and playing .flac files with the mpv media player

Suppose we want to show the list of .flac files in our ~/Music directory in dmenu, and we want to reproduce the one we select on the mpv media player. Here is what we could write:

#!/bin/bash 
choice="$(find ~/Music -type f -name "*.flac" | sort -n | dmenu -i -l 10 -p "Play:")" 
[ -n "${choice}" ] && mpv --no-video "${choice}" &> /dev/null &

In the script, we define the choice variable, which is assigned the value resulting from piping three commands. The first is find, which we use to retrieve all files with the “.flac” extension in the ~/Music directory. The resulting list is passed to the sort utility, which, in this case, sorts items numerically. Finally, we pass the output of sort to dmenu, which we invoke with the -i, -l and -p options. The first, makes the menu search case-insensitive; the second, as we saw, creates a vertical list; with the third, instead, we specify the text of the prompt.

The element we choose in the menu, is “stored” in the choice variable. We test if the latter is empty (it could be if we don’t select anything): if the variable is not empty, we use its value as argument to the mpv player. We store the script somewhere in our PATH. Here is the result of running it:

Selecting flac files from dmenu
Selecting flac files from dmenu

Another example: using dmenu to perform web queries

Here is another trivial script which allow us to perform web queries using Google and Firefox:

#!/bin/bash 
query="$( echo "" | dmenu -p "Search: " <&- )" 
[ -n "${query}" ] && firefox https://www.google.com/search?q="${query}" &

To get the query keyword, and store it in the query variable, we use, once again, command substitution. In this case, we don’t want to display a list in dmenu, therefore we just pipe an empty string to it. Since there are no items displayed in dmenu, we use the <&- redirection operator to close the standard input of the application. From bash manpage:

 

The redirection operator

[n]<&word

is used to duplicate input file descriptors. If word expands to one or more digits, the file descriptor denoted by n is made to be a copy of that file descriptor. If the digits in word do not specify a file descriptor open for input, a redirection error occurs. If word evaluates to ‘’, file descriptor n is closed. If n is not specified, the standard input (file descriptor 0) is used.



If the query variable is not empty, we construct a URL using its value, and we launch a Firefox instance in the background to open it. Here is the demonstration:

Closing thoughts

Dmenu is a free and open source dynamic menu for X typically used on minimal window managers setups. It is mostly used as an application launcher, but in this article we saw how it can be easily customized to perform a variety of tasks. The community shares many personalized dmenu scripts on platforms like GitHub. Feel free to explore them to create your own!



Comments and Discussions
Linux Forum