Beyond Aliases — define your development workflow with custom bash scripts

Being a Linux user for just over 10 years now, I can’t imagine my life with my aliases.

Aliases help with removing the repetition of commonly-used commands on a system.

For example, here’s some of my own that I use with the Laravel framework:

Bash
alias a="php artisan"
alias sail='[ -f sail ] && bash sail || bash vendor/bin/sail'
alias stan="./vendor/bin/phpstan analyse"

You can set these in your ~/.bashrc file. See mine in my dotfiles as a fuller example.

However, I recently came to want greater control over my development workflow. And so, with the help of videos by rwxrob, I came to embrace the idea of learning bash, and writing my own little scripts to help in various places in my workflow.

A custom bash script

For the example here, I’ll use the action of wanting to “exec” on to a local docker container.

Sometimes you’ll want to get into a shell within a local docker container to test / debug things.

I found I was repeating the same steps to do this and so I made a little script.

Here is the script in full:

Bash
#!/bin/bash

docker container ls | fzf | awk '{print $1}' | \
xargs -o -I % docker exec -it % bash

Breaking it down

In order to better understand this script I’ll assume no prior knowledge and explain some bash concepts along the way.

Sh-bang line.

the first line is the “sh-bang”. It basically tells your shell which binary should execute this script when ran.

For example you could write a valid php script and add #!/usr/bin/php at the top, which would tell the shell to use your php binary to interpret the script.

So #!/usr/bash means we are writing a bash script.

Pipes

The pipe symbol: |.

In brief, a “pipe” in bash is a way to pass the output of the left hand command to the input of the right hand command.

So the order of the commands to be ran in the script is in this order:

  1. docker container ls
  2. fzf
  3. awk ‘{print $1}’
  4. xargs -o -I % docker exec -it % bash

docker container ls

This gives us the list of currently-running containers on our system. The output is the list like so (I’ve used an image as the formatting gets messed up when pasting into a post as text) :

fzf

So the output of the docker container ls command above is the table in the image above, which is several rows of text.

fzf is a “fuzzy finder” tool, which can be passed a list of pretty much anything, which can then be searched over by “fuzzy searching” the list.

In this case the list is each row of that output (header row included)

When you select (press enter) on your chosen row, that row of text is returned as the output of the command.

In this image example you can see I’ve typed in “app” to search for, and it has highlighted the closest matching row.

awk ‘{print $1}’

awk is an extremely powerful tool, built into linux distributions, that allows you to parse structured text and return specific parts of that text.

'{print $1}' is saying “take whatever input I’m given, split it up based on a delimeter, and return the item that is 1st ($1).

The default delimeter is a space. So looking at that previous image example, the first piece of text in the docker image rows is the image ID: `”df96280be3ad” in the app image chosen just above.

So pressing enter for that row from fzf, wil pass it to awk, which will then split that row up by spaces and return you the first element from that internal array of text items.

xargs -o -I % docker exec -it % bash

xargs is another powerful tool, which enables you to pass what ever is given as input, into another command. I’ll break it down further to explain the flow:

The beginning of the xargs command is as so:

Bash
xargs -o -I %

-o is needed when running an “interactive application”. Since our goal is to “exec” on to the docker container we choose, interactive is what we need. -o means to “open stdin (standard in) as /dev/tty in the child process before executing the command we specify.

Next, -I % is us telling xargs, “when you next see the ‘%’ character, replace it with what we give you as input. Which in this case will be that docker container ID returned from the awk command previously.

So when you replace the % character in the command that we are giving xargs, it will read as such:

Bash
docker exec -it df96280be3ad bash

This is will “exec” on to that docker container and immediately run “bash” in that container.

Goal complete.

Put it in a script file

So all that’s needed now, is to have that full set of piped commands in an executable script:

Bash
#!/bin/bash

docker container ls | fzf | awk '{print $1}' | xargs -o -I % docker exec -it % bash

My own version of this script is in a file called d8exec, which after saving it I ran:

Bash
chmod +x ./d8exec

Call the script

In order to be able to call your script from anywhere in your terminal, you just need to add the script to a directory that is in your $PATH. I keep mine at ~/.local/bin/, which is pretty standard for a user’s own scripts in Linux.

You can see how I set my own in my .bashrc file here. The section that reads $HOME/.local/bin is the relevant piece. Each folder that is added to the $PATH is separated by the : character.

Feel free to explore further

You can look over all of my own little scripts in my bin folder for more inspiration for your own bash adventures.

Have fun. And don’t put anything into your scripts that you wouldn’t want others seeing (api keys / secrets etc)

Connecting to a VPN in Arch Linux with nmcli

nmcli is the command line tool for interacting with NetworkManager.

For work I sometimes need to connect to a vpn using an .ovpn (openvpn) file.

This method should work for other vpn types (I’ve only used openvpn)

Installing the tools

All three of the required programs are available via the official Arch repositories.

Importing the ovpn file into your Network Manager

Once you’ve got the openvpn file on your computer, you can import it into your Network Manager configuration with the following command:

# Replace the file path with your own correct one.
nmcli connection import type openvpn file /path/to/your-file.ovpn

You should see a message saying that the connection was succesfully added.

Activate the connection

Activating the connection will connect you to the VPN specified with that .ovpn file.

nmcli connection up your-file

If you need to provide a password to your vpn connection, you can add the --ask flag, which will make the connection up command ask you for a password:

nmcli connection up your-file --ask

Disconnect

To disconnect from the VPN, just run the down command as follows:

nmcli connection down you-file

Other Links:

Network Manager on the Arch Wiki.

Installing and setting up github cli

What is the github cli

The Github CLI tool is the official Github terminal tool for interacting with your github account, as well as any open source projects hosted on Github.

I’ve only just begun looking into it but am already trying to make it part of my personal development flow.

Installation

You can see the installation instructions here, or if you’re running on Arch Linux, just run this:

sudo pacman -S github-cli

Once installed, you should be able to run the following command and see the version you have installed:

gh --version

Authenticating

Before interacting with your github account, you will need to login via the cli tool.

Generate a Github Personal Access Token

Firstly, I generate a personal access token on the Github website. In my settings page I head to “Developer Settings” > “Personal Access Tokens” > “Tokens (classic)”.

I then create a new “classic” token (just my preference) and I select all permissions and give it an appropriate name.

Then I create it and keep the page open where it displays the access token. This is for pasting it into the terminal during the authentication flow next.

Go through the Github CLI authentication flow

Start the authentication flow by running the command:

gh auth login

The following highlights are the options I select when going through the login flow. Your needs may vary.

What account do you want to log into?
> Github.com
> Github Enterprise Server

What is your preferred protocol for Git operations?
> HTTPS
> SSH

Upload your SSH public key to your Github account?
> /path/to/.ssh/id_rsa.pub
> Skip

How would you like to authenticate Github CLI?
> Login with a web browser
> Paste an authentication token

I then paste in the access token from the still-open tokens page, and hit enter.

You should see it correctly authenticates you and displays who you are logged in as.

Check out the official documentation to see all of the available actions you can perform on your account.

Updating PHP versions in Ubuntu 20.04

Installing an older PHP version and switching to it in Ubuntu.

For an older PHP project, I needed to install an older version of PHP. This is what I did to set that up.

Installing a different PHP version

sudo add-apt-repository ppa:ondrej/php
sudo apt-get update
sudo apt-get install -y php7.1

Rebinding php to required version

Some of these binds are probably not need. I think the main ones, at least for my use case, were php and phar.

sudo update-alternatives --set php /usr/bin/php7.1
sudo update-alternatives --set phar /usr/bin/phar7.1
sudo update-alternatives --set phar.phar /usr/bin/phar.phar7.1
sudo update-alternatives --set phpize /usr/bin/phpize7.1
sudo update-alternatives --set php-config /usr/bin/php-config7.1

For some reason the --set flag stopped working, so I had to use:

sudo update-alternatives --config php
sudo update-alternatives --config phar

etc. And update each one with the terminal prompt options for each.

p.s. If using PHP-FPM, you could also set up different server conf files and point the FPM path to the version you need. My need was just because I was using the command line in the older project.