Skip to content

Commit 4c0d9fb

Browse files
article: debian linux post install scripts
resolve: #34
1 parent 873abd0 commit 4c0d9fb

1 file changed

Lines changed: 344 additions & 0 deletions

File tree

Lines changed: 344 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,344 @@
1+
---
2+
title: Use the latest Dev Tools on a Stable Debian Linux
3+
date:
4+
created: 2026-03-29
5+
updated: 2026-03-30
6+
authors:
7+
- practicalli
8+
categories:
9+
- debian
10+
tags:
11+
- operating-system
12+
- bash
13+
- scripting
14+
draft: false
15+
---
16+
17+
![Practicalli Debian Linux Logo](https://github.com/practicalli/graphic-design/blob/live/topic-images/debian-linux-logo-name.png?raw=true){align=right loading=lazy style="width:240px"}
18+
19+
I use Debian Linux as there is a huge advantage to having a stable and low maintenance operating system. This allows me to focus and get more things done.
20+
21+
The constraint of a stable operating system is that some of the latest versions of development tools and programming languages may not be available as part of the distributions package manager.
22+
23+
Simple bash scripts were created to install the latest development tools, made effectively one-liner's where the [Download Release Artifacts (DRA)](#Git} project could be used. The scripts were very simple even when falling back to `curl` with a few basic Linux commands.
24+
25+
These shell scripts and the DRA tool are used to install editors, programming languages (e.g. Clojure, Rust, Node.js), Terminal UI (TUI's) tools for development or system administration and even the odd desktop app.
26+
27+
A `debian-linux-post-instal.sh` script was created update all the Debian packages, reading packages to add and remove from a plain text file.
28+
29+
A `dev-tools-install.sh` calls each script that installs the latest versions of each development tool, programming language, TUI and desktop app.
30+
31+
[Practicalli dotfiles - Debian-Linux](https://github.com/practicalli/dotfiles/tree/main/debian-linux) contains all the scripts, along with a few manual steps that have not been scripted (mainly UI / UX configuration).
32+
33+
<!-- more -->
34+
35+
## Debian Packages
36+
37+
I created a simple bash script to add packages for tools and applications I commonly use.
38+
39+
The script reads a list of packages from two text files, one listing packages to add and another listing packages to remove.
40+
41+
Each list is just a text file, making it very easy to maintain. I keep both lists in alphabetic order so its easy to check which packages will be added or removed.
42+
43+
The post install script also includes the setup of the clipboard package, based on which windowing system is currently used, i.e. X11 or Wayland.
44+
45+
The script also sets `kitty` as the default terminal. Kitty would already be installed as it is part of the add package list.
46+
47+
Finally the script tidies up packages not required, `autopurge`, and deletes all the downloaded packages, `autoclean`.
48+
49+
> NOTE: A Debian Linux install adds a few packages that I do not wish to use, or replaces packages when I have alternative package preferences. E.g. I remove Evolution as I do not need a local mail server, I also use LightDM rather than GDM3 for the GUI greeter and display manager.
50+
51+
52+
### Package Post Install Script
53+
54+
A `while` loop is used to read through a package list file one line at a time, each time calling the `apt-get` command.
55+
56+
`sudo apt-get --yes --ignore-missing install <package-name>` is used to install each package in turn.
57+
58+
The `--ignore-missing` flag skips a package if it is already installed and at the latest version.
59+
60+
The `--yes` flag automatically confirms the install, even when otherwise prompted to confirm the install of the recommended package dependencies.
61+
62+
> NOTE: `apt-get` is the back-end command used by `apt`, the Debian Linux package manager. `apt-get` is ideal for use in scripts and has a little less overhead than `apt` itself.
63+
64+
??? EXAMPLE "Debian Linux Post Install Script"
65+
```shell
66+
#!/usr/bin/env bash
67+
68+
# Batch install Debian Linux packages used by Practicalli
69+
# Skip packages if they are already installed
70+
71+
# NOTES:
72+
# - apt-get backend used as features of apt UI not required for scripts
73+
74+
# Package lists to process
75+
add="debian-linux-post-install-packages-add.list"
76+
purge="debian-linux-post-install-packages-purge.list"
77+
78+
## Update available Debian packages
79+
echo
80+
echo "# ---------------------------------------"
81+
echo Update available Debian packages
82+
sudo apt update
83+
echo "# ---------------------------------------"
84+
echo
85+
86+
# Install additional Debian packages
87+
while read -r line
88+
do
89+
echo "# ---------------------------------------"
90+
echo Install "$line"
91+
sudo apt-get --yes --ignore-missing install "$line"
92+
echo "# ---------------------------------------"
93+
done < "$add"
94+
echo
95+
96+
echo "# ---------------------------------------"
97+
echo Install System Clipboard tool - X11 or Wayland
98+
./clipboard.sh
99+
echo "# ---------------------------------------"
100+
echo
101+
102+
echo "# ---------------------------------------"
103+
echo Configure Kitty as default terminal
104+
sudo update-alternatives --set x-terminal-emulator "/usr/bin/kitty"
105+
echo "# ---------------------------------------"
106+
echo
107+
108+
# Remove additional Debian packages
109+
while read -r line
110+
do
111+
echo
112+
echo "# ---------------------------------------"
113+
echo Purge "$line"
114+
echo "# ---------------------------------------"
115+
echo
116+
sudo apt-get purge --yes --ignore-missing "$line"
117+
done < "$purge"
118+
echo
119+
120+
echo "# ---------------------------------------"
121+
echo Uninstall unnecessary Debian packages
122+
sudo apt-get autopurge
123+
echo "# ---------------------------------------"
124+
echo
125+
126+
echo "# ---------------------------------------"
127+
echo Remove Debian package files from cache
128+
sudo apt-get clean
129+
echo "# ---------------------------------------"
130+
echo
131+
```
132+
133+
## Development tools
134+
135+
I use Neovim and Emacs editors, a range of development tools and several programming languages.
136+
137+
I created a simple bash script for each each development tool. Each script downloads and installs the binary or AppImage file for that tool.
138+
139+
Where relevant, the script also updates shell completions (for either bash or zsh, depending on which is currently being used).
140+
141+
The following tools are used to simplify the scripts:
142+
143+
- [Download Release Assets (DRA)](https://github.com/devmatteini/dra) downloads the latest stable release from a GitHub repository
144+
- [Uv](https://docs.astral.sh/uv/) to install python packages, using `uv tool install` to avoid the need for a Python virtual environment.
145+
- Curl with a tools specific install script, e.g. Clojure CLI.
146+
- Curl with a little scripting magic as a fall-back
147+
148+
[Practicalli Dotfiles](https://github.com/practicalli/dotfiles/) contains a [debian-linux](https://github.com/practicalli/dotfiles/tree/main/debian-linux) directory with the individual tool scripts organised in sub-directories:
149+
150+
- `app` for desktop applications
151+
- `cli` for command line tools
152+
- `language` for programming languages, e.g. Clojure, Rust, Node.js
153+
- `tui` terminal UI apps used for system administration and supporting development tools
154+
155+
156+
### GitHub Releases
157+
158+
Most development tools and TUI's have binaries or AppImages available from their GitHub Release pages.
159+
160+
[Download Release Assets (DRA) tool](https://github.com/devmatteini/dra) downloads and installs the latest release from the specified GitHub repository.
161+
162+
Unfortunately I cant use DRA to install DRA, so curl is used to download the DRA install script
163+
164+
Alternatively, use curl and a bit of scripting magic to get the URL of the latest Debian package, using curl again to download the Debian package and the Apt package manager to install the downloaded .deb file.
165+
166+
> NOTE: dra runs on Linux (x86_64, armv6, arm64), macOS (x86_64, arm64) and Windows.
167+
168+
??? EXAMPLE "Use Curl to install DRA via its install script"
169+
```shell
170+
#!/usr/bin/env bash
171+
172+
echo
173+
echo "# ---------------------------------------"
174+
echo "DRA - Download Release Assests from GitHub"
175+
curl --proto '=https' --tlsv1.2 -sSf https://raw.githubusercontent.com/devmatteini/dra/refs/heads/main/install.sh | sudo bash -s -- --to /usr/local/bin
176+
177+
178+
# Generate shell command completion
179+
if [[ $SHELL == "/bin/bash" ]]; then
180+
mkdir -p ~/.local/share/bash-completion/completions/
181+
dra completion bash > ~/.local/share/bash-completion/completions/dra
182+
183+
elif [[ $SHELL == "/usr/bin/zsh" ]]; then
184+
mkdir -p ~/.local/share/zsh-completion
185+
dra completion zsh > ~/.local/share/zsh-completion/_dra
186+
else
187+
echo "Unknown SHELL, Ripgrep completions will not be generated"
188+
exit
189+
fi
190+
191+
echo
192+
echo "Dra version: $(dra --version)"
193+
echo "# ---------------------------------------"
194+
echo
195+
```
196+
197+
198+
??? EXAMPLE "Use Curl to install DRA via the Debain package"
199+
DRA publishes a `.deb` file as part of each release.
200+
201+
Curl is first used to find the URL of the .deb package from the latest GitHub release.
202+
203+
Use `apt` the Debian package manager to install the DRA package.
204+
205+
```shell
206+
#!/usr/bin/env bash
207+
208+
echo
209+
echo "# ---------------------------------------"
210+
echo "DRA - Download Release Assests from GitHub"
211+
212+
DOWNLOAD_URL=$(curl -s https://api.github.com/repos/devmatteini/dra/releases/latest | grep browser_download_url | grep .deb | cut -d '"' -f 4)
213+
214+
curl -s -L -o ~/tmp/dra.deb "$DOWNLOAD_URL"
215+
216+
sudo apt install /tmp/dra.deb
217+
218+
# Generate shell command completion
219+
if [[ $SHELL == "/bin/bash" ]]; then
220+
mkdir -p ~/.local/share/bash-completion/completions/
221+
dra completion bash > ~/.local/share/bash-completion/completions/dra
222+
223+
elif [[ $SHELL == "/usr/bin/zsh" ]]; then
224+
mkdir -p ~/.local/share/zsh-completion
225+
dra completion zsh > ~/.local/share/zsh-completion/_dra
226+
else
227+
echo "Unknown SHELL, Ripgrep completions will not be generated"
228+
exit
229+
fi
230+
231+
echo
232+
echo "Dra version: $(dra --version)"
233+
echo "# ---------------------------------------"
234+
echo
235+
```
236+
237+
??? INFO "Deconstructing the Debian package Shell Script"
238+
239+
| Command | Description |
240+
| --- | --- |
241+
| `curl -s https://api.github.com/repos/USERNAME/REPO/releases/latest` | Fetch latest release data (JSON) from the GitHub repository |
242+
| `grep browser_download_url` | Filters JSON output returning only lines including a download URL |
243+
| `grep .deb` | Filters URLs to only those that are .deb files |
244+
| `cut -d '"' -f 4` | Extract URL from the filtered JSON response |
245+
| `curl -s -L -o ~/tmp/filename.deb "$DOWNLOAD_URL"` | Download `.deb` file to specified directory |
246+
247+
248+
DRA can also be used as a TUI to install a specific version of a tool or automatically install the latest version.
249+
250+
![Download Release Assets from GitHub](https://github.com/devmatteini/dra/raw/main/assets/demo.gif){loading=lazy}
251+
252+
### Neovim
253+
254+
DRA is used to download the latest AppImage and install it globally, so I can use `nvim` for the `practicalli` user account and the `root` account for operating system administration.
255+
256+
The script explicitly specifies the AppImage asset, otherwise DRA will extract and install only the `nvim` client and neglects to include the Neovim runtime.
257+
258+
??? EXAMPLE "Install latest stable Neovim AppImage"
259+
```shell
260+
#!/usr/bin/env bash
261+
262+
# Install the current release version of Neovim from GitHub for all users
263+
264+
echo
265+
echo "# ---------------------------------------"
266+
echo "Neovim hyper-configurable editor - installed for all users"
267+
268+
# install the nvim.appimage (automatic only installs nvim and not runtime)
269+
# rename file to `nvim` the standard executable name
270+
sudo dra download --select nvim-linux-x86_64.appimage --install --output /usr/local/bin/nvim neovim/neovim
271+
272+
echo
273+
echo "Neovim version: $(neovim --version)"
274+
echo "# ---------------------------------------"
275+
echo ""
276+
```
277+
278+
A similar script is used to install a nightly release of the AppImage.
279+
280+
This script specifies `--tag nightly` to get the latest nightly release.
281+
282+
The script installs the AppImage into `~/.local/bin` as it is only needed for the `practicalli` user account, for testing my Neovim configuration.
283+
284+
??? EXAMPLE "Install latest nightly Neovim AppImage"
285+
```shell
286+
#!/usr/bin/env bash
287+
288+
# Install the pre-release version of Neovim from GitHub, for the current user
289+
290+
echo
291+
echo "# ---------------------------------------"
292+
echo "Neovim hyper-configurable editor"
293+
echo "- installed only for current user"
294+
295+
# Install nvim.appimage nightly release tag and rename to nvim-nightly
296+
dra download --tag nightly --select nvim-linux-x86_64.appimage --install --output ~/.local/bin/nvim-nightly neovim/neovim
297+
298+
echo
299+
echo "Neovim pre-release version: $(nvim-nightly --version)"
300+
echo "# ---------------------------------------"
301+
echo
302+
```
303+
304+
### Emacs
305+
306+
Emacs usually has the latest version available as a Debian package.
307+
308+
if need a newer version or I want to try bleeding features then I will compile Emacs from its source code, choosing the relevant branch for the version I require.
309+
310+
[Building Emacs from source code](https://practical.li/blog/build-emacs-from-source-on-debian-linux/) takes a few simple steps and can be configured to create a customised set of features and even a custom desktop icon.
311+
312+
!!! TIP "Emacs Plus is recommended for MacOS users"
313+
[Emacs Plus](https://github.com/d12frosted/homebrew-emacs-plus) is configurable formulae for Homebrew, providing more features and flexibility than Homebrew's own Emacs formulae.
314+
315+
## But Arch Linux is Awesome
316+
317+
I have used 'rolling' distributions and spent 2025 testing out Arch Linux as an alternative operating system. The initial learning curve was not too steep and getting going only took a weekend. However, the maintenance burden was much greater and became a continual distraction.
318+
319+
Part of the maintenance headache was using Btrfs (failed during a recovery) and Hyprland (which introduced lots of breaking changes).
320+
321+
I found some core Arch Linux tools confusing. `packman` command options did not feel intuitive and the docs didn't clarify what the flags letters stood for. If I continued to use Arch Linux I would have wrapped pacman with a shell script or Makefile tasks.
322+
323+
Using the AUR community repository I also found confusing, there are several tools to access AUR and it wasn't clear from the official docs how to add these tools without first adding AUR (catch 22 scenario).
324+
325+
The AUR community is a big part of adding the latest development tools. Without the AURA then Arch Linux didn't feel significantly up to date for software development..
326+
327+
Usually the Arch Linux docs are very comprehensive, but can drowned the reader in options (some outdated) and yet not provide enough guidance or a clear and simple approach.
328+
329+
I never did figure out a nice way to manage my SSH Keys in Arch Linux when I wasnt using a Gnome desktop.
330+
331+
Arch Linux meets the needs of many people, but Debian Linux the ideal operating system for me.
332+
333+
> NOTE: As I have used Debian Linux since 1995 (30 years at time of writing) I have a strong affinity and confidence using it as my operating system. Debian has never let me down.
334+
335+
---
336+
Thank you.
337+
338+
[:globe_with_meridians: Practical.li Website](https://practical.li){target=_blank .md-button}
339+
340+
[:fontawesome-brands-github: Practical.li GitHub Org](https://github.com/practicalli){target=_blank .md-button}
341+
[:fontawesome-brands-github: practicalli-johnny profile](https://github.com/practicalli-johnny){target=_blank .md-button}
342+
343+
[:fontawesome-brands-mastodon: @practicalli@clj.social](https://clj.social/@practicalli){target=_blank .md-button}
344+
[:fontawesome-brands-twitter: @practical_li](https://twitter.com/practcial_li){target=_blank .md-button}

0 commit comments

Comments
 (0)