UP | HOME

Shell Hacks

Bash

Every Script Needs:

(Note this is opinion, not fact of best practices) `set -e` tells the script to stop when it hits errors (Bash doesn't) `set -u` tells the script to stop on unset variables `set -o pipefail` prevents the script continuing if part of the pipe fails

So:

`set -euo pipefail` in all scripts!

Iteration

Increment counter variable:

i=$((i+1))
((i=i+1))
let "i=i+1"

Decrement counter variable:

i=$((i-1))
((i=i-1))
let "i=i-1"

Parameter Expansion

The value of parameter will be substituted.

parameter will be expanded, and then the output will be truncated according to the pattern word from the beginning of parameter

parameter will be expanded, and then the output will be truncated according to the pattern word at the end of the parameter

This last one is particularly useful for removing file extensions.

Case syntax

case EXPRESSION in
        PATTERN)
                statement;
                statemnet;;
        PATTERN2)
                statement;;
esac

For loop

for $i in $list
        do
                command
done

If statement

if [ condition ]; then
        command
elseif
        command
else
        command
fi

Conditionals

Do note there is a difference between [ ] and [ [ ] ]. [ ] is the test shell builtin. Double brackets is calling an external command.

Conditions

[ -z STRING ] : empty string
[ -n STRING ] : non empty string
[ STRING == STRING ] : equal
[ STRING != STRING ] : not equal
[ NUM -eq NUM ] : equal
[ NUM -ne NUM ] : not equal
[ NUM -lt NUM ] : less than
[ NUM -le NUM ] : less than or equal
[ NUM -gt NUM ] : greater than
[ NUM -ge NUM ] : greater than or equal
[ STRING =~ STRING ] : regexp
&& : and
|| : or
! : not

File conditions

[ -e FILE ] : exists
[ -r FILE ] : readable
[ -h FILE ] : symlink
[ -d FILE ] : directory
[ -w FILE ] : writable
[ -s FILE ] : size is >0 bytes
[ -f FILE ] : file
[ -x FILE ] : executable
[ FILE -nt FILE ] : newer than
[ FILE -ot FILE ] : older than
[ FILE -ef FILE [ : same files

Read a File Line by Line

  1. Default
while read -r line; do
        cmd1
        cmd2
done < file
  1. Use IFS to specify field limiter
while IFS= read -r line; do
        cmd1
        cmd2
done < file
  1. Note: read -p workaroung

You cannot use read -p to get user input while inside a while loop. For using data from a file to creat prompts my workaround is to read a file into an array.

declare -a LINES
while read -r line; do
        LINES+=("$line")
done < file

for p in "$LINES[@]"
do
        read -p "$p " a
        printf "%s %s\n" "$p $a"
done

Regexp

. : matches any single character ^ : matches a term at the beginning of a paragraph or line [a-e] : matches any characters but a-e bye$ : matches bye if it occurs at the end of a line [abcde] : matches any single a, b, c, d, e

  • : signifies a range of characters

() : group regular expressions {n} : matches the previous character exactly n times {n,m} : matches the previous character minimum n time, maximum m times {n,} : matches the previous character n or more times \| : matches the regexp preceeding or following ? : matches the preceeding character 1 or 0 times

* : match preceeding character 0 or more times

  • : match precedding character 1 or more times

! : do not match the following regexp \ : escape special chars \b : match word boundary \n : match line break \t : match tab \w : equivalent to [a-zA-Z0-9_] \W : matches the opposite of above \d : matches digits 0-9 [:alpha:] : equivalent to [A-Za-z] [:digit:] : equivalent to [0-9] or [\d] [:alnum:] : equivalent to [A-Za-z0-9]

Write shell scripts with options:

  1. getopt (create options for a shell script)

This is a standalone command, so getopt will need to be installed for this to work. This provides the possibility for GNU style long options

PARAMS=`getopt -o a::bc: --long arga::,argb,argc: -n 'myscript.sh' -- "$@"`
eval set -- "$PARAMS"

while true ; do
    case "$1" in
        -a|--arga)
            case "$2" in
                "") ARG_A='some default value' ; shift 2 ;;
                *) ARG_A=$2 ; shift 2 ;;
            esac ;;
        -b|--argb) ARG_B=1 ; shift ;;
        -c|--argc)
            case "$2" in
                "") shift 2 ;;
                *) ARG_C=$2 ; shift 2 ;;
            esac ;;
        --) shift ; break ;;
        *) echo "Unknown option!" ; exit 1 ;;
    esac
done

Date: 2024-09-15