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
The Set Built-in
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 -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
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}"