# Installing GNOME extension via CLI

Intending to reuse the installation process of a GNOME extension, I wrote the following script:

#!/bin/bash
# It installs a target gnome shell extension defined via url

STORE_URL="https://extensions.gnome.org/extension-data"
EXTENSIONS_PATH="$HOME/.local/share/gnome-shell/extensions/" ZIP="gnome-extension.zip" cd ~/Downloads wget$STORE_URL/$1 -O ./$ZIP
UUID=$(unzip -c$ZIP metadata.json | grep uuid | cut -d \" -f4)

if [[ ! -d $EXTENSIONS_PATH/$UUID ]]; then
mkdir $EXTENSIONS_PATH/$UUID
unzip -q ./$ZIP -d$EXTENSIONS_PATH/$UUID gnome-shell-extension-tool -e$UUID
fi

rm $ZIP gnome-shell --replace &  It expects to receive as argument the target extension zip name, one available from official GNOME extensions index. The zip file, after downloaded, will be unzipped in its UUID directory inside GNOME extensions' location and then enable. Is there something else could be done to improve this installation process? Any of the executed commands could be improved or code get better readability? ## 1 Answer First off, install Shellcheck and routinely run it on your scripts, or configure your editor to run it automatically. Now, Shellcheck is pretty rigorous and you would be forgiven for not solving all its warnings, but at the very least be aware of them. #!/bin/bash  On some systems there’s a more up to date bash installed in a different location. In general you’d want to use #!/usr/bin/env bash  Though in the case of Bash on Linux I think yours is OK.1 Next, enable stricter error checking: set -euo pipefail  From help set: • -e Exit immediately if a command exits with a non-zero status. • -u Treat unset variables as an error when substituting. • -o pipefail the return value of a pipeline is the status of the last command to exit with a non-zero status, or zero if no command exited with a non-zero status Regarding your variables, there’s a convention to use UPPER_CASE for environment variables, and snake_case for others. Not mandatory, but a nice way to distinguish them. wget$STORE_URL/$1 -O ./$ZIP


Even though in this specific case there are no spaces or other special characters in your variables, always double-quote them to prevent string splitting — there’s simply no reason ever not to do so, and it gets you into the habit of spotting potential errors when quotes are missing.

cd ~/Downloads


That directory might or might not exist. As we’re talking about a GNOME environment, you might want to use something like $(xdg-user-dir DOWNLOAD) to get the actual download directory. The same is usually true for the path ~/.local/share, but the GNOME shell extensions documentation makes it sound as if the path is actually hard-coded. rm$ZIP


This will not be executed if the script failed earlier due to an error. To ensure cleanup on error or if the user aborted the script, replace this with a trap.

Resulting script:

#!/usr/bin/env bash

# Install a target gnome shell extension defined via url

set -euo pipefail

store_url="https://extensions.gnome.org/extension-data"
extensions_path="$HOME/.local/share/gnome-shell/extensions/" zip="gnome-extension.zip" cd "$(xdg-user-dir DOWNLOAD)"
wget "$store_url/$1" -O "$zip" trap 'rm "$zip"' ERR INT TERM EXIT

uuid=$(unzip -c "$zip" metadata.json | grep uuid | cut -d \" -f4)

if [[ ! -d "$extensions_path/$uuid" ]]; then
mkdir "$extensions_path/$uuid"
unzip -q "$zip" -d "$extensions_path/$uuid" gnome-shell-extension-tool -e "$uuid"
fi

gnome-shell --replace &


1 On macOS, on the other hand, it’s a bad idea since the Bash version of /bin/bash is eternally stuck at 3.2 due to licensing issues, and if you want to use any more recent Bash features you need to rely on a user-installed version with a different path.

• Thanks for the revision! Trap, double quotes and error checking will get in to my bash code mores – artu-hnrq Jun 3 at 1:21