Bash Scripts
Examples of using Bash in a script
Loop over an array, read in from a file
#!/bin/bash
# A BASH script makes the first command line argument available as $1, the second as $2 and so on.
# The command run, exactly as it was called but without the command line arguments, is stored in $0.
#
# The dirname command returns the directory name part of a filename.
# Note that the directory and/or file do not actually exists; dirname simply strips the last component of a file path.
# For example, "dirname /a/b/c" will echo "/a/b", "dirname ../a/b/c" will echo "../a/b", "dirname ../" will echo "." and so on.
#
# The directory the BASH script is located in can be retrieved using "dirname $0"
#
# Note although the cd command is used, the script will not change directory and any other calls within it are still relative to the current working directory.
#
# This is useful when you need to reference a file that sits next to the script.
cd $(dirname "$0")
# Read in from fileName and store in varName
# IFS is the field separator
IFS=$'\n' read -d '' -r -a varName < ./fileName
# Loop through items in varName
for i in "${varName[@]}"; do
echo "processing ${i}"
printf "\n\n\n"
done
Compare two different files
#!/bin/bash
IFS=$'\n' read -d '' -r -a fileAResource < /tmp/fileA-resource
IFS=$'\n' read -d '' -r -a fileBResource < /tmp/fileB-resource-sco
# FILEA_TOTAL_COUNT holds the total number of resource in FILEA
FILEA_TOTAL_COUNT=0
# FILEA_ORPHANED_COUNT holds the number of orphaned resource
FILEA_ORPHANED_COUNT=0
# FILEA_ORPHANED holds the names of the orphaned resource
FILEA_ORPHANED=()
# FILEB_TOTAL_COUNT holds the total number of resource in FILEB
FILEB_TOTAL_COUNT=0
# FILEB_ORPHANED_COUNT holds the number of orphaned resource
FILEB_ORPHANED_COUNT=0
# FILEB_ORPHANED holds the names of the orphaned resource
FILEB_ORPHANED=()
# Loop through items in fileAResource
for i in "${fileAResource[@]}"; do
EXISTS_IN_FILEB=$(cat /tmp/fileB-resource | grep "$i")
# If the string is null (empty)
if [ -z "$EXISTS_IN_FILEB" ]; then
FILEA_ORPHANED+=("$i")
((FILEA_ORPHANED_COUNT++))
fi
((FILEA_TOTAL_COUNT++))
done
# Loop through items in fileBResource
for i in "${fileBResource[@]}"; do
EXISTS_IN_FILEA=$(cat /tmp/fileA-resource | grep "$i")
# If the string is null (empty)
if [ -z "$EXISTS_IN_FILEA" ]; then
FILEB_ORPHANED+=("$i")
((FILEB_ORPHANED_COUNT++))
fi
((FILEB_TOTAL_COUNT++))
done
if [[ $1 == "fileA-debug" ]]; then
echo "${FILEA_ORPHANED[@]}"
fi
if [[ $1 == "fileB-debug" ]]; then
echo "${FILEB_ORPHANED[@]}"
fi
echo "There are $FILEA_ORPHANED_COUNT (out of $FILEA_TOTAL_COUNT) orphaned resource (resource that exist in FILEA but not FILEB)"
echo "There are $FILEB_ORPHANED_COUNT (out of $FILEB_TOTAL_COUNT) orphaned resource (resource that exist in FILEB but not FILEA)"
Compare two different resource endpoints
#!/bin/bash
# Set field separator as our commands return each resource on a newline
IFS=$'\n'
TA_RESOURCES=$( // command to get resources // )
TA_RESOURCES=($TA_RESOURCES)
TB_TOKEN=$( // command to get token // )
TB_RESOURCES=$(curl -s -H "Authorization: Bearer $TB_TOKEN" -H "Content-Type: application/json" "$ENDPOINT" | jq -r '.[].name')
TB_RESOURCES=($TB_RESOURCES)
TB_TOTAL=0
TB_ORPHANED_TOTAL=0
TB_NON_ORPHANED_TOTAL=0
TB_ORPHANED=()
TA_TOTAL=0
TA_ORPHANED_TOTAL=0
TA_NON_ORPHANED_TOTAL=0
TA_ORPHANED=()
for i in "${TB_RESOURCES[@]}"; do
if echo ${TA_RESOURCES[@]} | grep -q -w "$i"; then
# IS in array
((TB_NON_ORPHANED_TOTAL++))
else
# IS NOT in array
TB_ORPHANED+=()
((TB_ORPHANED_TOTAL++))
fi
((TB_TOTAL++))
done
for i in "${TA_RESOURCES[@]}"; do
if echo ${TB_RESOURCES[@]} | grep -q -w "$i"; then
# IS in array
((TA_NON_ORPHANED_TOTAL++))
else
# IS NOT in array
TA_ORPHANED+=()
((TA_ORPHANED_TOTAL++))
fi
((TA_TOTAL++))
done
if [[ $1 == "ta-debug" ]]; then
echo "${TA_ORPHANED[@]}"
fi
if [[ $1 == "tb-debug" ]]; then
echo "${TB_ORPHANED[@]}"
fi
echo "TB -- (Total: $TB_TOTAL) (Orphaned: $TB_ORPHANED_TOTAL) (Not Orphaned: $TB_NON_ORPHANED_TOTAL)"
echo "TA -- (Total: $TA_TOTAL) (Orphaned: $TA_ORPHANED_TOTAL) (Not Orphaned: $TA_NON_ORPHANED_TOTAL)"
Check example configuration file contains all relevant variables from local configuration file
#!/bin/bash
EXAMPLE_FILE=local.env.example
LOCAL_FILE=local.env
if [[ ! -f "$LOCAL_FILE" ]]; then
echo "local environment file doesn't exist"
exit 0
fi
if [[ ! -f "$EXAMPLE_FILE" ]]; then
echo "example environment file doesn't exist"
exit 1
fi
LOCAL_CONTENTS=$(cat ./${LOCAL_FILE} | grep export | sed 's/^export //g' | awk -F'=' '{print $1}')
EXAMPLE_CONTENTS=$(cat ./${EXAMPLE_FILE} | grep export | sed 's/^export //g' | awk -F'=' '{print $1}')
ERRS=()
# Process contents of EXAMPLE_CONTENTS, line-by-line.
# IFS is empty as we don't want to separate the contents on each line
while IFS='' read -ra ADDR; do
for i in "${ADDR[@]}"; do
# If the env var is commented out, ignore it
if [ "${i:0:1}" == "#" ]; then
continue
fi
EXISTS_IN_EXAMPLE=$(echo "$EXAMPLE_CONTENTS" | grep "$i")
# If the string is null (empty)
if [ -z "$EXISTS_IN_EXAMPLE" ]; then
ERRS+=("$i")
fi
done
done <<< "$LOCAL_CONTENTS"
if [[ ! ${#ERRS[@]} -eq 0 ]]; then
echo "The following environment variables are defined in $LOCAL_FILE, but not in $EXAMPLE_FILE:"
echo "${ERRS[@]}"
exit 1
fi
Rename files
#!/bin/bash
# For every file in the current directory
for file in *; do
# Ignore files with a .sh extension
[[ $file == *.sh ]] && continue
# Use sed/regex to remove everything from '-' to '.' (inclusive) and replace with '.'
NewName=$(echo ${file} | sed 's/-.*\././')
# Change spaces to \[space]
NoSpaces=$(echo ${NewName} | sed 's/ /\\ /g')
echo "Moving '$file' to $NoSpaces"
mv "$file" "$NoSpaces"
done
rsync script
#!/bin/bash
# Find running rsync processes that aren't the one we spawn (grep) with this command
RUNNING="$(ps -ef | grep rsync | grep --invert-match 'grep')"
# Only spawn more rsync jobs if there aren't some already running
if [[ -z "$RUNNING" ]]; then
echo "Running rsync commands"
rsync -aqz --remove-source-files --no-o --no-g --no-perms /source/files /destination > /dev/null 2>&1 &
else
echo "Not running rsync commands, there is one already running"
fi
Using command line flags
#!/bin/bash
# Get the directory of the bash script
cd $(dirname $BASH_SOURCE)
DIR=$(pwd)
APP_ONE_ENV=prod
APP_TWO_ENV=lve
# If number of arguments is less than 10, the flags haven't been supplied
if [ $# -lt 10 ]
then
echo "usage: ./script.sh -l {login true/false} -e {escalate true/false} -s {resourceid} -j {JIRA ticket} -u {requesting user}"
exit 1;
fi
if [[ $(appone config show-context) != ${APP_ONE_ENV} ]]; then
echo "appone not configured for correct environment"
exit 1
fi
if [[ $(apptwo -c) != ${APP_TWO_ENV} ]]; then
echo "apptwo not configured for correct environment"
exit 1
fi
while getopts l:e:s:j:u: flag
do
case "${flag}" in
l) login=${OPTARG};;
e) escalation=${OPTARG};;
s) resourceid=${OPTARG};;
j) jiraticket=${OPTARG};;
u) username=${OPTARG};;
esac
done
if [ "$login" == "true" ]; then
# Login to appone
appone auth login
# Login to apptwo
apptwo auth login
fi
STATE=$(appone resource get "$resourceid" -o json | jq .state)
if [ ! "$STATE" == "Deleted" ]; then
echo "Resource is not in a Deleted state"
exit 1
fi
if [ "$escalation" == "true" ]; then
ESCALATION_OUTPUT=$(apptwo escalate)
echo "$ESCALATION_OUTPUT"
fi
Create a mini-CLI programme
#!/bin/sh
# Get the directory of the bash script
cd $(dirname $BASH_SOURCE)
DIR=$(pwd)
COMMAND=$1
RESOURCE_NAME=$2
VERSION=$3
FILE_CREATE=~/dir/aSubDIR/test-resource.json
FILE_UPDATE=~/dir/aSubDIR/test-resource-update.json
REGEX='help'
# Perform a regex match of the string
if [[ $COMMAND =~ $REGEX ]];
then
echo "available commands:
- list
- listByOwner
- countByOwner
- approve {resource} {version}
- cancel {resource} {version}
- cancel-termination {resource}
- create {resource}
- delete {resource}
- get {resource}
- job-status {resource}
- history {resource}
- reject {resource} {version}
- update {resource}
"
exit 0;
fi
if [ "$COMMAND" == 'list' ]; then
# Print executed command to the terminal
set -x
cmd resources list
# Disable printing executed commands to the terminal
set +x
exit 0;
fi
if [ "$COMMAND" == 'listByOwner' ]; then
set -x
cmd resources list --verbose -o json | jq -r --arg USER "$2" '.[] | select(.createdBy==$USER) | .name'
set +x
exit 0;
fi
if [ "$COMMAND" == 'countByOwner' ]; then
set -x
cmd resources list --verbose -o json | jq '.[].createdBy' | sort | uniq -c | sort -r
set +x
exit 0;
fi
# If number of arguments is less than 2
if [ $# -lt 2 ]
then
echo "usage: ./cmd-commands.sh {command} {resource-name} [version]"
exit 1;
fi
if [ "$COMMAND" == 'approve' ]; then
# If the string is null (empty)
if [ -z "$VERSION" ]
then
echo "Version not provided"
exit 1;
fi
set -x
cmd resources approve $RESOURCE_NAME --version $VERSION --reason "An optional reason for why this is approved"
set +x
exit 0;
fi
if [ "$COMMAND" == 'cancel' ]; then
if [ -z "$VERSION" ]
then
echo "Version not provided"
exit 1;
fi
set -x
cmd resources cancel $RESOURCE_NAME --version $VERSION --reason "A valid reason for why the update is being cancelled"
set +x
exit 0;
fi
if [ "$COMMAND" = 'cancel-termination' ]; then
set -x
cmd resources cancel-termination $RESOURCE_NAME --reason "TEST-1245 cancel termination"
set +x
exit 0;
fi
if [ "$COMMAND" == 'create' ]; then
set -x
cmd resources create $RESOURCE_NAME -f $FILE_CREATE --reason "TEST-0000 testing new commands"
set +x
exit 0;
fi
if [ "$COMMAND" == 'delete' ]; then
set -x
cmd resources delete $RESOURCE_NAME --reason "TEST-1234 deleting resource"
set +x
exit 0;
fi
if [ "$COMMAND" == 'get' ]; then
set -x
cmd resources get $RESOURCE_NAME
set +x
exit 0;
fi
if [ "$COMMAND" == 'history' ]; then
set -x
cmd resources history $RESOURCE_NAME
set +x
exit 0;
fi
if [ "$COMMAND" == 'update' ]; then
set -x
cmd resources update $RESOURCE_NAME -f $FILE_UPDATE --reason "TEST-0000 testing new commands - update"
set +x
exit 0;
fi