basename & DIRNAME
basename "$FILE"
filename="$(basename $FILE)"
path="$(dirname $FILE)"
BOOLEAN
Bash doesn’t have built-in true
and false
boolean values that can be used to test for validity. It’s often just as clear to use 0
or 1
for false and true, respectively.
“For interactive use, like one-liners, make sure to leave a space after !
, or it will do history expansion. ((! foo))
works, so does ! ((foo))
. ((foo || bar))
works as expected”[1]. Also, remember that bash considers an exit code of 0
success while an exit code of 1
is failure. If you are working with true being equal to 1
and false being equal to 0
your may have to adjust some bash-y expectations.
#!/bin/bash
flag=0
if (( flag )); then
echo "Condition is true";
fi
false=0
true=1
((false)) && echo false
((true)) && echo true
((!false)) && echo not false
((!true)) && echo not true
(Source: stackoverflow.com)
conditionals
if...then...elif...else...fi
if TEST-COMMAND1; then
STATEMENTS1
elif TEST-COMMAND2; then
STATEMENTS2
elif [ $test_var -ge 3 -a $test_var -lt 11 ]; then
STATEMENTS3
else
STATEMENTS4
fi
FIND
Find files that have been changed in the last 24 hours.
find /var/lib/ -mtime -1 -ls
-1
means anything changed one day or less ago. +1
means anything that has changed at least one day ago. Having only 1
means exactly one day ago.
(Source: stackoverflow.com)
LOOPS
Loop through a list of files.
while read patch; do
patch -p1 -f < ${patch} &>> $PATCH_LOG
done < <(ls -l ${PATCH_SUBDIR}/*.patch)
parameter expansions (substitutions)
For even more reference, see the holy grail of bash PEs.
Replace a character in a string with another character.
$ VER=4.19.87
$ NEWVER="${VER//./_}"
$ echo "$NEWVER"
4_19_87
PATHS
When you experience odd behavior with finding or not finding an installed or uninstalled program, you may need to refresh your remembered locations.
hash -r
See the following references: man hash | pip3 is looking for a wrong path | what does hash -r command do? | what is the purpose of the hash command
PRINTING
printf
an exclamation mark.
Option 1: use single-quoted strings.
printf 'Unable to find config file. Exiting!'
Option 2: add to the end of the string, outside of the quotes
printf "Unable to find config file. Exiting" !
Option 3: print ASCII representation of ! character
printf "\041"
Option 4: Mix double quotes with single quotes (extension to Option 1)
printf "Unable to find config file. Exiting"'!'" (that prints an exclamation mark just fine.\n"
Option 5: use a format string
printf "This (%s) is an exclamation mark%s\n" ! !
printf
Two Variables
printf "%s %s" % "${MYSTRING1}" "${MYSTRING2}"
sequence
for i in $(seq 1 $END); do printf "$i\n"; done
set
Unless specifically required to not be, the second line of all Bash scripts ought to be: set -euf -o pipefail
Echo on for single command
set -x
ls $mydir
set +x
NOTE: In Jenkins, set -x
is the default. This echoes all commands. Override by putting the following at the top of the “Execute Shell” build step:
#!/bin/bash +x
Strings
Change Case – Lower/upper
(I do not use “downcase” – it’s “lower case“ – that word needs to be exonerated from its duty of describing a letter case.)
Entire Word
I’m not even going to try to out-do this answer.
Though I will drop it here for quick reference:
$ myvar="True"
$ echo "$myvar" | tr '[:upper:]' '[:lower:]'
true
First Letter
foo="$(tr '[:lower:]' '[:upper:]' <<< ${foo:0:1})${foo:1}"
String Substitution
Again, great post on StackOverflow. Dropping it here for quick reference.
#!/bin/bash
firstString="I love Suzi and Marry"
secondString="Sara"
echo "${firstString/Suzi/$secondString}"
# prints 'I love Sara and Marry'
Style guide
Formatting
shfmt
$ shfmt -w -i 4 -sr <file(s) or path...>
How-to
man page
TLDP BASH Programming How-To
TLDP Advanced Bash-Scripting Guide
Google’s Shell Style Guide
Linter
shellcheck
Tests
-f
Check if a file exists
FILE=/tmp/myfile.txt
if [[ -f "$FILE" ]]; then
echo "$FILE exists"
fi
-z
Check if a variable is empty
if [ -z "$var" ]; then
printf '$var is empty\n';
else
printf '$var is not empty\n';
fi
SUDO
One-liner including password
NOTE: Do not use this if you do not want others to see your script or bash history, which includes your user’s sudo password.
Use case: SSH to a Clonezilla Server that is already running and already has a specific user created on it. This user can SSH but the files on the Clonezilla live system are read-only so you can not edit /etc/sudoers file to specify NOPASSWD for your user.
$ echo <password> | sudo -S <command>
Trickster: to avoid exposing the password on the command history, start the command with a SPACE character.
Check for sudo in your shell scripts
if [ $(id -u) -eq 0 ]; then
printf "You are root\n"
else
printf "You are not root\n"
fi
trap
For easier cleanup, use trap
Variables
Default Value
MyVar="${DEPLOY_ENV:-default_value}"