1 minute read

There’s no need to use tr, sed and awk to trim whitespace from variables as per these examples (NB: one of the popular options is described here – but not the most popular at the time of writing).

Bash: The Bourne-Again Shell

We’ll use OPTARG as the variable, purely because I used it to strip spaces when parsing options in a script.

# Trim leading whitespace
OPTARG="${OPTARG#"${OPTARG%%[![:space:]]*}"}"

# Trim trailing whitespace
OPTARG="${OPTARG%"${OPTARG##*[![:space:]]}"}"

These look quite complicated, but are easier to understand with a worked example:

OPTARG="     The quick brown fox   "
echo ">$OPTARG<"
# Outputs >     The quick brown fox   <

First what does the “internal” substitution do…

echo ">${OPTARG%%[![:space:]]*}<"
# Outputs >     <

This removes the longest substring from the end of OPTARG that is not whitespace followed by any character ([![:space:]]*) — i.e. remove everything from the first non-whitespace character to the end; effectively leaving all the whitespace from the beginning of OPTARG.

This whitespace prefix is then used as a pattern to remove from the front of OPTARG:

echo ">${OPTARG#"${OPTARG%%[![:space:]]*}"}<"
# Outputs >The quick brown fox   <

Trimming trailing whitespace does the opposite.

echo ">${OPTARG##*[![:space:]]}<"
# Outputs >   <

This removes from OPTARG the longest substring from the front of OPTARG  – matching the pattern any character followed by a non-whitespace character (*[![:space:]]). I.e. remove everything except the trailing spaces.

Next these trailing spaces are used as the pattern to remove from the end of OPTARG:

OPTARG="${OPTARG%"${OPTARG##*[![:space:]]}"}"
# Outputs >     The quick brown fox<

Running both of these together trim leading and then trailing spaces:

OPTARG="     The quick brown fox   "
OPTARG="${OPTARG#"${OPTARG%%[![:space:]]*}"}"
OPTARG="${OPTARG%"${OPTARG##*[![:space:]]}"}"
echo ">$OPTARG<"
# Outputs >The quick brown fox<

Fixing parsing errors

I have found that on some platforms (I forget which), removing the quotes around the internal substitution does not always work. It may be a script parsing issue, making the following not work. Keeping quotes around the internal substitution works:

OPTARG="     The quick brown fox   "
OPTARG="${OPTARG#${OPTARG%%[![:space:]]*}}"
OPTARG="${OPTARG%${OPTARG##*[![:space:]]}}"
echo ">$OPTARG<"
# Might not work on all UNIX, but should output >The quick brown fox<

Both work on OSX and Linux from where I write this blog. Maybe not on AIX or a different version of bash. Could be something about POSIX compliance. If you find a UNIX platform where it doesn’t work, let me know.

Comments