Linux: Associating file types to applications
Associating file types (extensions, in Windows) to applications is a fundamental functionality of desktop environments.
Some people may still have a troubled experiences while doing so; some others may want to script the operating system configuration. For both, I’m writing a small article about how to make such association via commandline, using standard Unix programs.
- Association by extension
Desktop environments of any operating systems provide a graphical mean of associating file types to applications (“Open with…” or similar); this includes Linux.
There is an underlying difference between Windows and Linux, though. Windows performs associations via file extension, while Linux typically does it in a more sophisticated way, via the so-called MIME type (also known as “Media type”).
In Linux desktop environments, (some) standards are specified by the freedesktop.org association. This includes the related tools, which are therefore common across all the distributions.
As an example, let’s suppose we want to associate Markdown files to Visual Studio Code.
Finding the desktop file
When an application is installed in Linux, typically, a desktop file is installed, which contains informations necessary to integrate it into the desktop environment; the files are typically created under
As a first step, we need to identify the desktop file; there are a few ways to accomplish this, some of whom may succeed with some installed applications, and some with other ones.
A simple search by filename will work most of the times:
# Case-insensitive search (`iname`). # $ find /usr/share/applications -iname '*code*' /usr/share/applications/code-url-handler.desktop /usr/share/applications/code.desktop
Alternatively, we can search the program or the executable names (in the latter case, watch out for symlinks!):
$ grep -Ri 'visual studio code' /usr/share/applications /usr/share/applications/code-url-handler.desktop:Name=Visual Studio Code - URL Handler /usr/share/applications/code.desktop:Name=Visual Studio Code $ grep -R "/code" /usr/share/applications /usr/share/applications/code-url-handler.desktop:Exec=/usr/share/code/code --no-sandbox --open-url %U /usr/share/applications/code.desktop:Exec=/usr/share/code/code --no-sandbox --unity-launch %F /usr/share/applications/code.desktop:Exec=/usr/share/code/code --no-sandbox --new-window %F /usr/share/applications/bamf-2.index:code-url-handler.desktop /usr/share/code/code --no-sandbox --open-url %U true /usr/share/applications/bamf-2.index:code.desktop /usr/share/code/code --no-sandbox --unity-launch %F Code false
Insane engineers may inspect the package contents instead (for the lulz, of course!):
# Download the VSC package. # $ apt download code # Extract the `data.tar.*` archive, which contains the files copied directly during the installation # of the package. # $ ar xv code_*.deb data.tar.xz # Now look for the desktop file! # $ tar tvf data.tar.xz | grep "/usr/share/applications" -rw-r--r-- root/root 340 2020-12-16 17:28 ./usr/share/applications/code-url-handler.desktop -rwxr-xr-x root/root 533 2020-12-16 17:28 ./usr/share/applications/code.desktop
In all the cases, the target file is very easily recognized as
Finding the MIME type
Now that we know the desktop file, we’ll need to find the MIME type. This can be done trivially by using the
mimetype program; as an example, we’ll download a markdown file:
$ wget -q https://raw.githubusercontent.com/saveriomiroddi/zfs-installer/master/README.md $ mimetype README.md README.md: text/markdown
The MIME type is therefore
As long as the extension is correct, there’s no problem, but for the curious, keep in mind that it’s easy to trick
mimetype by using false extensions. Let’s download a GIF file, storing it with an incorrect extension:
$ wget -q https://github.com/saveriomiroddi/zfs-installer/raw/master/demo/demo.gif -O demo.fakeext.txt $ mimetype demo.fakeext.txt demo.fakeext.txt: text/plain
What’s interesting here, is that
mimetype actually has several heuristics; it just picked the first:
$ mimetype -a demo.fakeext.txt demo.fakeext.txt: text/plain demo.fakeext.txt: image/gif demo.fakeext.txt: application/octet-stream
In cases like this, we look only at the file content and ignore the extension (“magic”!):
$ mimetype --magic-only demo.fakeext.txt demo.fakeext.txt: image/gif
Finally, there’s also the standard tool
file, which inspects the content by default:
$ file --mime demo.fakeext.txt demo.fakeext.txt: image/gif; charset=binary
Generally speaking, if the file is correctly named, a basic
mimetype invocation will suffice.
Registering the association
Knowing both the desktop file and the MIME type, we can now… connect the dots 😬:
$ xdg-mime default code.desktop text/markdown
That’s all! Now, when opening the file (either via GUI, or
xdg-open), Visual Studio Code will execute.
Let’s double check it!:
$ xdg-mime query default text/markdown code.desktop
Association by extension
In some cases, the desktop environment may be fooled by the MIME type. No fear!
An example of this, are files in the MAFF format, the former Firefox pages archive format, which are technically ZIP files. When opening them, the desktop environment detects that they’re archives, and opens the default archive manager.
In this case, we can enforce a certain mime type by matching the extension:
$ glob_pattern='*.maff' $ mime_type="application/x-maff" $ file_comment="Maff File" $ sudo tee /usr/share/mime/packages/maff.xml << XML <?xml version="1.0" encoding="UTF-8"?> <mime-info xmlns="http://www.freedesktop.org/standards/shared-mime-info"> <mime-type type="$mime_type"> <comment>$file_comment</comment> <glob pattern="$glob_pattern"/> </mime-type> </mime-info> XML $ update-mime-database /usr/share/mime
The desktop environment will now recognize anything matching the glob
One of my many favourite aspects of Linux, is that there is a program for any operation one may want to perform.
In this article, we’ve used a few tools used to configure file associations; this can be used to compensate unfortunate deficiencies of desktop environments, but also, for programmatically configuring systems (like I do!).
Happy system hacking!