Skip to content

Instantly share code, notes, and snippets.

@ljfranklin
Last active November 11, 2018 17:35
Show Gist options
  • Star 3 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ljfranklin/99fc9af42aa732b33525 to your computer and use it in GitHub Desktop.
Save ljfranklin/99fc9af42aa732b33525 to your computer and use it in GitHub Desktop.
## Bash Prog Intro Notes
http://tldp.org/HOWTO/Bash-Prog-Intro-HOWTO.html
http://tldp.org/LDP/abs/html/
http://mywiki.wooledge.org/BashPitfalls
## Intro:
I feel like writing bash is like building something with hot glue.
When try it for the first time, you'll probably make a big mess and burn yourself.
As you get a little more experienced, you can slap things together really quickly but the end result won't be very sturdy or pretty.
This guide provides a cheatsheet for bash functions that I use frequently.
The commands start fairly simply with a handful of more advanced commands and gotchas towards the end.
## Basic Commands:
Write stdout, stderr, both to file:
```
$out_cmd > stdout.log
$err_cmd 2> stderr.log
$both_cmd &> combined.log
```
Assign output of command to variable
```
output="$(echo 'hello!')"
```
Positional Parameters
```
./my-script hello world
echo "$0" # ./test, script path
echo "$1" # hello, first positional arg
echo "$2" # world, second arg
echo "$#" # 2, total number of args
echo "$*" # "hello world", expands all args as a single word
echo "$@" # "hello" "world", expands all args as separate words
# shift
echo "$1" # hello
shift # discard first arg, slide remaining args to left
echo "$1" # world
```
Parameter Substitution:
```
ARG="${1:-default_value}" # `:-` returns LHS if not null, RHS otherwise
: ${ENV_VARIABLE:=default_value} # `:=` sets ENV_VARIABLE to `default_value` if ENV_VARIABLE is null.
# The leading `:` prevents the shell from trying to run the value.
: ${ENV_VARIABLE:?ENV_VARIABLE must be set} # exit immediately if ENV_VARIABLE is null, trailing error message is optional
```
Integer Arithmetic
```
echo "$((2+2))" # 4
a=1
(( a++ )) # sets `a` to 2
echo "$(( a++ ))" # still prints 2, then sets value to 3. Be careful with pre vs post increment!
```
If statements
```
if [ $condition0 ]; then
command0
elif [ $condition1 ]; then
command1
else
command2
fi
```
For loops
```
# print 1 through 10 inclusive
for i in $(seq 1 10); do # be sure not to quote "$(...)"
echo "$i"
done
# print each arg
for arg in "$@"; do
echo "$arg"
done
```
Iterate over lines in a file
```
while read line; do
echo "$line"
done < input.txt
```
Case statements
```
#!/bin/bash
case "$1" in
start)
echo "Starting..."
;;
stop | shutdown)
echo "Stopping..."
;;
*)
# default case
echo "ERROR: Unrecognized option '$1'"
echo "Usage: my_script {start|stop|shutdown}"
;;
esac
```
Test Operators
```
# integers
if [ "$a" -eq "$b" ] # equal
if [ "$a" -ne "$b" ] # not equal
if [ "$a" -gt "$b" ] # greater than
if [ "$a" -lt "$b" ] # less than
# strings
if [ "$a" == "$b" ]
if [ "$a" != "$b" ]
# variables
if [ -z "$1" ] # succeeds if $1 is unset
if [ -n "$1" ] # succeeds if $1 is set
# boolean operators
if [ ! $condition ] # invert result
if [ $condition0 ] && [ $condition1 ] # and
if [ $condition0 ] || [ $condition1 ] # or
## file operators
if [ -e $file ] # true if file or directory exists
if [ -f $file ] # true if file exists, false for directories
if [ -d $dir ] # true if directory exists, false for files
```
Get the previous command's exit code:
```
somd_cmd
echo "$?"
```
Capture PID and write to file:
```
# replace current process with another process
echo $$ > $pidfile
exec some_process
# write pid of background process
some_process &
echo $! > $pidfile
```
## Text processing commands
Print the n-th item in a line
```
WORDS="this is only a test"
echo "$WORDS" | cut -d ' ' -f3 # prints "only", index starts at 1
echo "$WORDS" | cut -d ' ' -f1-3 # prints "this is only"
echo "$WORDS" | cut -d ' ' -f1,f5 # prints "this test"
CSV="first,last,address"
echo "$CSV" | cut -d ',' -f2 # prints "last", changes delimiter
```
Replace changes in string
```
CSV="first,last,address"
echo "$WORDS" | sed 's/,/\n/g' # prints "first\nlast\naddress"
```
Get leading or trailing lines in file
```
head -n1 ./some_file # prints first line in file
tail -n1 ./some_file # prints last line in file
tail -f ./process.log # streams file contents as new lines are added, useful for debugging
```
Extract file or directory names
```
FILE_PATH=/home/foo/my-file.txt
FILE="$(basename $FILE_PATH)" # "my-file.txt"
DIR="$(dirname $FILE_PATH)" # "/home/foo"
```
Search with regex
```
# print lines matching regex
grep 'value' ./some-file
echo "$VAR" | grep 'value' # can be used with pipes
grep -i 'vAluE' ./some-file # case insensitive
grep -v 'value' ./some-file # inverse, print lines not matching regex
# check for running process name
ps ax | grep mysql
```
## Advanced commands
Regex
Notes:
- Uses POSIX regex, e.g. `[[:digit:]]` instead of `\d`
- To avoid unexpected behavior, always store regex in a variable and
do not quote the variable after the `=~` operator.
- Regex is tough to read at the best of times, bash syntax makes it harder.
Please use sparingly.
```
REGEX='[[:digit:]]{1,3}\.[[:digit:]]{1,3}\.[[:digit:]]{1,3}\.[[:digit:]]{1,3}'
if [[ "10.10.0.255" =~ $REGEX ]]; then # do not surround regex variable in quotes
echo "Match!"
else
echo "No match..."
fi
# capture groups
REGEX='[a-z]+_([a-z]+)' # capture letters following `_`
[[ "first_last" =~ $REGEX ]]
last_name="${BASH_REMATCH[1]}" # [0] is the full match, [1] is the first capture group
```
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment