Although GNOME, in its 3.x iteration has been the object of many debates, due to its non-traditional desktop paradigm, it is probably the most used desktop on Linux. The default file manager included in GNOME is Nautilus (the application new name is “Files”). In this tutorial we will see how we can extend the file manager with functionalities provided by custom scripts.
In this tutorial you will learn:
- How to use custom scripts to extend Nautilus functionalities
Software Requirements and Conventions Used
Category | Requirements, Conventions or Software Version Used |
---|---|
System | Distribution-independent |
Software | The Nautilus file manager |
Other | No specific requirements are needed to follow this tutorial |
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 |
Creating the scripts directory
The first thing we want to do is to create the directory that will host our scripts: ~/.local/share/nautilus/scripts
. Once placed in this directory, the scripts will automatically appear in the Nautilus context menu displayed when we select one or more files:
$ mkdir -p ~/.local/share/nautilus/scripts
In the command above we used the -p
switch (short for --parents
) to be sure that all directories in the specified path are created as needed, and no errors are generated if some of them already exists. With our directory in place, we can start working on our very useful scripts: notice that they will be correctly included in the Nautilus context menu only if they are made executable
. Before writing code we should learn to know some variables we can use inside the scripts: they are the main way we can interact with the status of the file manager, accessing very useful information.
Nautilus scripts variables
For our scripts to be somehow useful, it should be possible to interact with the file manager status and be able to reference, for example, the path and the names of selected files, or the current working directory: we can access these information via some variables set exactly for this purpose. Let’s see them.
First of all we have the NAUTILUS_SCRIPT_SELECTED_FILE_PATHS
variable. As should always happen, the variable name is pretty self-explanatory: this variable holds the full filesystem path of the files currently selected in the file manager. The variable value is a string; the file paths are delimited by the use of newline
characters.
Another very useful variable is NAUTILUS_SCRIPT_SELECTED_URIS
. We can use this variable, like the one we just saw, to reference selected files, with one difference: the files are not referenced by their paths, but by their URI
, or “Unified Resource Identifier”. The role of this variable becomes evident when working on remote filesystems: in that case, simple paths will not work, and the NAUTILUS_SCRIPT_SELECT_FILE_PATHS
variable will be empty. In such situations, to access the files we also need to know the type of protocol in use: a file selected in the file manager via the sftp
protocol, for example, will be referenced as sftp://path/to/file
.
Finally, we have the NAUTILUS_SCRIPT_CURRENT_URI
and the NAUTILUS_SCRIPT_WINDOW_GEOMETRY
variables. The former contains the URI
of the directory opened in the file manger; the latter information about the geometry (width and height) and the position of the file manager window (eg: 631×642+26+23).
A practical example
As an example, we will build a very simple script: its purpose will be that of organize pictures selected in the file manager on the base of their creation date. In this case the script will be written in python
, a language that is supported by default on every distribution; we can, of course, also write bash scripts, or use any other supported scripting language.
Nowadays almost all digital images contains metadata we can use to retrieve all kind of information, like the type of camera or device used to create the picture and the settings used. What we are talking about are called exif
tags: what interests us in this case is the OriginalDateTime
field (36867). The script will be able to organize only the pictures that include that tag, and will rearrange them in directories created using the the “year/month name” pattern. Pictures containing no information will be placed in a directory called “unsorted”. Here is our script, we will save it as “organize.py”:
#!/usr/bin/env python3
"""
Author: Egidio Docile
Organize selected pictures by their creation date, using the exif
DateTimeOriginal tag
"""
import datetime
import os
from PIL import Image
DATETIME_ORIGINAL=36867
def main():
for path in os.getenv('NAUTILUS_SCRIPT_SELECTED_FILE_PATHS','').splitlines():
try:
exif_data = Image.open(path)._getexif()
except OSError:
continue
try:
date = datetime.datetime.strptime(exif_data[DATETIME_ORIGINAL], '%Y:%m:%d %H:%M:%S')
directory = os.path.join(date.strftime('%Y'), date.strftime('%B'))
except (KeyError, ValueError, TypeError):
directory = "unsorted"
os.makedirs(directory, exist_ok=True)
os.rename(path, os.path.join(directory, os.path.basename(path)))
if __name__ == '__main__':
main()
As you can see, we access and read the NAUTILUS_SCRIPT_SELECTED_FILE_PATHS
variable using the os.getenv
method, also providing an empty string as the default value, in case the variable is not set. We then used the splitlines
method to “explode” the string that is the value of the variable we just mentioned, into a list, using the newline character as delimiter. Finally we processed each file path in a for loop.
Of course the script can be improved, but let’s verify that it works. Once we place it in the ~/.local/share/nautilus/scripts
directory, we must make it executable by running:
$ chmod +x ~/.local/share/nautilus/scripts/organize.py
A new entry should appear in the file manager context menu, when files are selected:
And here is our script in action. We select the images we want to sort and click on “script/organize.py” in the context menu:
Using graphical dialogues in the scripts
There may be some cases in which our scripts, to work correctly, should be able to interact with the user, perhaps to ask confirmation before performing an operation. We can create such dialogues in our scripts, depending on the programming language we are using. When writing bash scripts, for example, we can use zenity
, a program to create GTK
dialogue boxes, that is usually included with a GNOME installation; if it is not we can install it using our favorite distribution package manager. On Fedora, for example we can run:
$ sudo dnf install zenity
On Debian-based distributions, instead we can use apt-get:
$ sudo apt-get install zenity
The package is also included in the “Extra” Archlinux repositories:
$ sudo pacman -S zenity
Let’s see an example on how to use zenity. This time we will write a bash script that, when executed, will lowercase the name of all selected files, after asking for, and receiving, the user confirmation.
#!/bin/bash
set -e
set -u
set -o pipefail
if zenity --question --title="Confirmation" --text="Should I run the script?"; then
echo "${NAUTILUS_SCRIPT_SELECTED_FILE_PATHS}" | while read -r selected_file; do
file="$(basename "$selected_file")"
mv "${file}" "${file,,}"
done
fi
In the script we invoked zenity
with the --question
, --title
and --text
options:
they are used respectively, to display a question dialogue, to set the title of the popup window that will be displayed, and to set the actual dialogue text. In this case, zenity exit code will be 0 if the user clicks on “yes” and 1 if he clicks on the “no” button. As we know, an exit code of 0 means that the command was executed successfully, therefore the code inside the if statement will be executed. To lowercase the file we used the ${parameter,,}
parameter expansion.
{loadposition in-article-ads-banner_31}
When using more sophisticated programming languages like python, we can access several type of graphical libraries, to generate dialogues, like TkInter which is the de-facto standard python GUI toolkit, or PyGObject to use the GTK
toolkit and libraries.
Conclusions
In this tutorial we saw how, in few easy steps, we can extend the Nautilus file manager using custom made scripts written in various type of programming languages. We saw where the scripts should be placed in the filesystem, and what are the variables we can reference inside them to get the paths or URI of the selected file, the URI of the directory opened in the file file manager and its geometry. Finally we two example, one written in python and the other in bash. In the latter, we saw also how to generate a graphical dialogue using zenity
: if you are curious about this utility, stay tuned, we will talk about it soon, here on linuxconfig.org.