Devop's Shell Programming Cheat Sheet

Stuck with a command? Try explainshell.com

The following posts deal with single Shell commands:

Pro Tip: Coloured grep output: kubectl get namespace | grep --color=always 'namespace\|planets'

First Things, First! The Shebang: #!

Shebang - the character sequence consisting of the characters number sign and exclamation mark (#!) at the beginning of a script. It is also called sha-bang, hashbang, pound-bang, or hash-pling.

Why is #!/usr/bin/env bash superior to #!/bin/bash?

Neither bash nor env need to be in the given location. So both seem to have the same flaw. It’s up to you!

Check the Linux Standard Base (LBS)

lsb_release -d                                                                                                            Description: Ubuntu 20.04.1 LTS

Using Conditional Expressions within Shell Scripts

This section shows some nice use-cases for conditional Expressions. To dive deeper into this topic please consult the official documentation of Bash Conditional Expressions.

Create a directory if not present

[ -d /opt/planets/bin ] || mkdir -p /opt/planets/bin

Test if environment variable exists - shell script: how to check if an environment variable exists, and get its value?

if [[ -z "${DEPLOY_ENV}" ]]; then
  MY_SCRIPT_VARIABLE="Some default value because DEPLOY_ENV is undefined"
else
  MY_SCRIPT_VARIABLE="${DEPLOY_ENV}"
fi

A simple check if a String variable isn't of size zero

if [ -n "${STOP_AND_REMOVE_CONTAINER}" ]
then
  docker stop planets-server || true
  docker rm planets-server || true
else
  echo "Skipping stop and remove of container."
fi

Browsing through existing code I found this nice snippet: Add trailing slash, if missing:

if [ "${DEST:LEN}" != "/" ]
then
        DEST=$DEST"/"
fi

Grab data from JSON files

This snippet shows how to handle JSON files with ./jq` like a pro:

JOB_ID=$(echo $JSON_DOCUMENT | jq -r '.build.jobs[0].jobId')

Note: You can download jq (a lightweight and flexible command-line JSON processor) here

Or via homebrew brew install jq on a Mac.

Use a default value in variable assignment

NETWORK_INTERFACE=${NETWORK_INTERFACE_ARG:-"en0"}

Read sensitive data from a file into a variable

token=$(<token.txt)
echo "$token

Replace all variables in a template with envrionment variables

eval "cat <<EOF
$(<planets-bot-deployment-template.yaml)
EOF
" > planets-bot-deployment.yaml

Read the version/any value of a (Java) properties file

export VERSION=$(grep version ../gradle.properties | cut -d'=' -f2)

Check if a variable is already set

if [ -z "$JAVA_HOME" ]; then
  echo "No JAVA_HOME set. Using default location for Java 8."
  export JAVA_HOME=$(/usr/libexec/java_home -v 1.8)
fi

Setting an environment temporarily for one command line

LOCAL_BUILD=true echo ${LOCAL_BUILD}

Unzip all files in a directory

find . -name '*.zip' -exec unzip {} \;

Create lot's of bogus data with dd

dd if=/dev/urandom bs=1024 count=$((50*1024)) > sample.bin

Check for OSX environment and IP address

if [ $(uname) == "Darwin" ]
then
  echo "OSX detected."
  NETWORK_INTERFACE=${NETWORK_INTERFACE_ARG:-"en0"}
  DOCKER_HOST_IP=$(ipconfig getifaddr ${NETWORK_INTERFACE})
else
  echo "Defaulting to Linux."
fi

Print a small usage info using a Shell function

usage() {
cat <<-END
Usage: $0 [-h] [-b backup]
  -h help
  -b {backup} to use
END
}if [[ -z "${BACKUP}" ]]; then
  usage
  exit 1
fi

The trickiest part was to get the formatting right: Multi-line string with extra space (preserved indentation).

Substring matching

if [[ ${DOCKER_HOST_IP} == 192.168.* ]]
then
    echo "local development environment detected."
fi

Create multiple directories with one command

Lately I found this nice snippet in a mongoDB online course to create three subdirectories for a cluster setup:

mkdir -p /data/db/m040/repl/{1,2,3}

The classical for loop

With strings, strings with dash and sub shell commands:

#!/bin/bash

for word in one two "with-dash" "subshell:" $(hostname -f); do
  echo $word
done

A while loop over files

#!/bin/zsh

while IFS= read -r -d '' dashboard
do
    echo "Processing ${dashboard}…"
    if yq -e eval '.metadata.namespace != "monitoring"' "${dashboard}" > /dev/null 2>&1; [ "$?" -eq 0 ]; then
        echo "Wrong namespace set in ${dashboard}, please assign the dashboard to namespace 'monitoring'"
        exit 1
    fi
    kubectl apply -f ${dashboard}
done < <(find "grafana/k8s" -name "*dashboard.yaml" -print0)

May the Shell be with you!