Bash Cheatsheet
Basics
Shebang:
#!/bin/bash
Executable Bit Set:
chmod +x my_script.sh
Best Practices
- Always use a shebang
- Always exit script with an exit status
- Use local variables in functions
Job Control
- What to do with a command
- & - Tells linux to start process in background so you can do something else
./start_my_long_script.sh &
do other things....
Useful Commands
SSHPASS:
- Used to be able to enter password
sshpass -p "PASSWORD" ssh -o StrictHostKeyChecking=no username@host
MKDIR:
# -p flag creates any other necessary directories
mkdir -p /var/log/system/apps/app.log
Convert to lower case:
SLIDES=${SLIDES,,}
Replace Spaces with underscore:
SLIDES=${SLIDES// /_}
Variables Input
Static:
- Names should be all upper case
- Don’t use any spaces
HOSTNAME="rtr-bfa1.example.net"
Dynamic (Output from command):
HOSTNAME=$(hostname)
Variables Output
NAME="James"
# Option 1
echo "my name is $NAME"
# Option 2 (useful if you have data right next to var)
echo "my name is ${NAME}!"
User Input
read -p "Enter a router hostname: " HOSTNAME
echo "SSHing into ${HOSTNAME}"
Arrays
FILES=(router1 router2 router3)
for FILE in "${FILES[@]}"
do
echo ${FILE}
touch $FILE
done
Exit Codes
- 0 == Success
- Every command returns an exist status 0-255
- $? Contains returncode of previously executed command
HOST="8.8.8.8"
ping -c 1 $HOST
RETURN_CODE="$?"
if [ "$RETURN_CODE" -eq "0" ]
then
echo "$HOST Reachable"
else
echo "$HOST Unreachable"
fi
Exit Code from Shell Script
- By default last command to be run will be the exit number
- Can be overridden - This also exits the script
if [ "$RETURN_CODE" -ne "0" ] ; then
echo "$HOST Unreachable"
exit 1
fi
exit 0
Command Output
- By default output of command will be echoed
# Suppress output to Null
ping -c 1 8.8.8.8 >/dev/null
# As above but also suppresses exit code
ping -c 1 8.8.8.8 > /dev/null 2>&1
Tests
If Statements
- Variables should be enclosed in quotes
HOSTNAME=$(hostname)
if [ "$HOSTNAME" = "COMPUTER1" ]
then
command1
command2
fi
Else
if [ condition-is-true ]
then
command1
else
command2
fi
Elif
if [ condition-is-true ]
then
command1
elif [ condition-is-true ]
then
command2
fi
For Loop
for LINE in FILE
do
echo "VAR: $LINE"
done
Samples:
- Move all jpg files and add date to file name ```bash PICTURES=$(ls *jpg) DATE=$(date +%F)
for PICTURE in PICTURES do echo “Renaming ${PICTURE} to ${DATE}-${PICTURE}” mv ${PICTURE} ${DATE}-${PICTURE} done
### Conditionals
**Check if file exists:**
```bash
[ -e /etc/prom/config.cfg ]
File Operator Conditionals:
| Condition | Description |
|---|---|
| -d FILE | True if file is a directory |
| -e FILE | True if file exists |
| -f FILE | True if file exists and is a regular file |
| -r FILE | True if file is readable by you |
| -s FILE | True if file exists and is not empty |
| -w FILE | True if the file is writable by you |
| -x FILE | True if file is executable by you |
String Conditionals:
| Condition | Description |
|---|---|
| -z STRING | True if string is empty |
| -n STRING | True if string is not empty |
| STRING1 = STRING2 | True if strings are equal |
| STRING1 != STRING2 | True if not equals |
Arthmetic Operators:
| Condition | Description |
|---|---|
| arg1 -eq arg2 | True if arg1 is equal to arg2 |
| arg1 -ne arg2 | True if arg1 is not equal |
| arg1 -lt arg2 | True if arg1 is less than arg2 |
| arg1 -le arg2 | True if arg1 is less or equal |
| arg1 -gt arg2 | True if arg1 is greater than arg2 |
| arg1 -ge arg2 | True if arg1 is greater or equal |
Script Arguments/Parameters
- $0 - script.sh (name of the script)
- $1 - Parameter1
- $2 - Parameter2
Sample Code:
echo "Executing script: $0"
echo "SSHing into: $1"
Loop through all Parameters:
for FOLDER in $@
do
echo "Moving folder: $FOLDER to /tmp/${FOLDER}"
mv $FOLDER /tmp/${FOLDER}
done
Logical Operators
AND = \&\&
- Second command only executes if first command return 0 ```bash mkdir /tmp/bak && cp test.txt /tmp/bak/
ping -c1 $HOST >/dev/null && echo “$HOST Reachable”
### OR = ||
```bash
cp test.txt /tmp/bak/ || cp test /tmp/
ping -c1 $HOST >/dev/null || echo "$HOST Unreachable"
OneLiners
; - Semicolon can be used to execute multiple commands on one line
cp test.txt /tmp/bak ; cp test2.txt /tmp/bak
Functions
- Variables created in function are by default available outside once the function has been called and the variable created.
# Option 1
function multiply() {
echo "Function"
}
multiply
# Option 2
multiply() {
echo "Function"
}
multiply
Arguments
- $1 - Argument1
- $2 - Argument2
- $@ - All Arguments ```bash function move_folders() { for FOLDER in $@ do mv $FOLDER /bak/${FOLDER} }
move_folders folder1 folder2 folder3
### Local Variables
```bash
local HOST="LOCALHOST"
Exit Status
- Only 0-255
- By default the value of the last command run
# Access exit code
my_function
echo $?
# Modify Exit Code
function my_function() {
return 0
}
Sample Script
- Backup File
function backup_file () {
if [ -f $1 ]
then
BACK="/tmp/$basename ${1}.$(date + %F).$$"
echo "Backing up ${1} to ${BACK}"
cp $1 $BACK
fi
}
backup_file /etc/hosts
if [ $? -eq 0 ]
then
echo "Backup succeeded!"
fi
Wildcards
-
-
- Matches zero or more characters
-
- ? - Matches exactly one character
- [ad] - Matches exactly one of the characters inside the brackets
- [!abc] - Matches and excludes one of the characters in the brackets
- [a-z] - Matches a range of characters
- [1-5] - Matches a range of numbers
- ”"- Escape character
- ?? - Matches all files that are 2 character long
mv *.jpg /tmp/bak/
mv 2022-22-??.txt /tmp/bak/
mv ca[nt]* /tmp/bak/ # (can, cat, candy, catch, etc)
mv [!sr]* /tmp/bak/ # Excludes any file that begins with s or r
[[:alpha:]] - Matches lower and upper case letters
[[:alnum:]] - Matches digits and numbers
[[:space:]] - Matches space/newline
[[:upper:]] - Matches all upper cases
\? - Matches question mark
Sample Code:
for HOST in gbg-*.host
do
OUTPUT=$(ssh $HOST "show hostname")
echo "$HOST - $OUTPUT"
Logging
- Ends up in /var/log/syslog or /var/log/messages
Facilities:
- Kern (Kernel)
- User (If unsure, use this)
- daemon
- auth
- local0 - Use for custom logs (custom scripts)
- local…
- local7 - Use for custom logs (custom scripts)
Severities:
- emerg
- alert
- crit
- err
- warning
- notice
- info
- debug
Sample Code:
# By default using notice severity and user severity
logger "Message"
# Customize:
logger -p local0.info "Message"
logger -t my_script -p- local0.info "Message"
Case Statements
- Replaces multiple if statements.
- Can be used for system startup scripts for example.
- Are case sensitive
ACTION="$1"
case "$ACTION" in
start)
docker-compose up -d
/usr/sbin/sshd
;;
stop)
docker-compose down
kill $(cat /var/run/sshd.pid)
;;
*)
echo "Usage: $0 start|stop" ; exit 1
;;
esac
# Allowing
case "$1" in
start|START|Start)
action...
# Accepts "y" "Y" "yes" "Yes" "YES" "yES"
case "$ANSWER" in
[yY] | [Yy] [eE] [sS])
While Loops
- break - Exits loop
- continue - Starts over at the top of the loop
- Use-Cases:
- While exit code of a command is NOT 0, continue
INDEX=1
while [ $INDEX -lt 10 ]
do
echo "Creating project-${INDEX}"
mkdir /usr/local/project-${INDEX}
((INDEX++))
done
Loop Forever (While True)
while true
do
command X
sleep 1
done
while ping -c 1 app1 >/dev/null
do
"App still up..."
sleep 5
done
echo "app down, continuing..."
Reading File Line by Line
- If you use a for loop to read a file line by line, it will read word for word. Use while loop for this.
- Will read /etc/fstab file
Option 1:
LINE_NUM=1
while read LINE
do
echo "${LINE_NUM}: ${LINE}"
((LINE_NUM++))
done < /etc/fstab
Option 2: - Reads output of a command
grep xfs /etc/fstab | while read LINE
do
echo "xfs: ${LINE}"
done
Debugging
x-trace: -x flag prints commands as they execute -e Exits script on error -v Prints the code line by line
# Option 1
#!/bin/bash -xe
# Option 2
set -x
Some code...
Some Code...
set +x
Troubleshooting Tips:
#!/bin/bash
DEBUG="echo"
$DEBUG ls
# If debug is false, ls is executed normally.