DEV Community

Kengah Ireneaus
Kengah Ireneaus

Posted on

A Month With Bash — Part 2: Expansions

A Month With Bash — Part 2: Expansions

Continuing from where I left off, the next thing I learned was special parameters in bash:

  • "$*"
  • $#
  • $?
  • $@
  • $N
  • $-
  • $0

Another important concept I picked up is how bash executes shell scripts. Bash is one of those languages that interprets each line as it goes — but it doesn't stop if a line fails. It continues on unless you explicitly set set -o pipefail (or -e, depending on what you want it to catch).

Generally, the procedure looks like this:

Tokenizing: splitting the line into tokens, usually split using the IFS value.

Brace expansion: a mechanism by which arbitrary strings can be generated.

echo file{1,2,3}.txt
## output: file1.txt file2.txt file3.txt
Enter fullscreen mode Exit fullscreen mode

Bash preserves the order from left to right.

Tilde expansion: this is where expansion of special symbols takes place.

  • ~ represents the HOME built-in variable
  • ~+ represents PWD, the current working directory
  • and others
DIR=~/Desktop # this is $HOME/Desktop
echo "$DIR"
Enter fullscreen mode Exit fullscreen mode

Parameter expansion: introduced with the $ symbol.

# ${} — the braces can be omitted for normal variables but not for array-type variables
Enter fullscreen mode Exit fullscreen mode

Command substitution: very important — it lets you assign the output of a command to a variable, and use commands inside if and for statements. Done with $(command to execute).

week_name="$(date +%A)" # gets the current day of the week
echo "$week_name"
Enter fullscreen mode Exit fullscreen mode

Generally, $() spawns a new shell instance, so it's advisable to avoid it where possible, for latency reasons.

Arithmetic expansion: just from the name, this allows evaluation of arithmetic expressions and substitution of the result. It starts with $(( expression )). There are some rules — bash doesn't support floating point arithmetic natively, so you'd reach for bc if you need it. I won't go deep into that here since this isn't a full bash tutorial.

Here's a simple BMI calculator I wrote while practicing this:

#!/usr/bin/env bash

# script calculates user's BMI and gives a recommendation

set -euo pipefail

# ---------------- read parameters ----------------
weight="$1"
height="$2"

bmi=$(bc -q <<< "scale=2; $weight / ($height^2)")

# ---------------- test ----------------
if (( $(bc -q <<< "$bmi < 18.5") )); then
    echo "UNDERWEIGHT"
elif (( $(bc -q <<< "$bmi < 25") )); then
    echo "normal weight"
elif (( $(bc -q <<< "$bmi < 30") )); then
    echo "overweight"
else
    echo "obese"
fi
Enter fullscreen mode Exit fullscreen mode

Process substitution: this saves the output of a process into a temporary file-like descriptor under /dev/fd/N. It lets you feed command output into programs that expect a file as input. Done with >(command) and <(command).

#!/usr/bin/env bash

# script demonstrates process substitution
# process substitution is when you want to use the output of a command
# as the input to a command that needs files as parameters

set -euo pipefail

# gets the difference between two texts without making temp files
echo "$(diff -p <(echo "hello mr beast") <(echo "hello mr beast."))"

# note: <(cmd) uses the output of a command as a file
# >(cmd) takes input from a program and feeds it to the command as a file
Enter fullscreen mode Exit fullscreen mode

Word splitting and globbing: occurs after expansion, only on unquoted values.

Next up: regex, grep/sed/awk, and moving into building actual projects.

Top comments (0)