Differences between revisions 13 and 28 (spanning 15 versions)
Revision 13 as of 2009-11-04 15:20:10
Size: 1898
Editor: GreyCat
Comment: Expand, clarify.
Revision 28 as of 2025-07-19 12:59:21
Size: 3497
Editor: GreyCat
Comment: add a mathematical trick for leading zero removal, normalize whitespace, add caveat about signed inputs
Deletions are marked like this. Additions are marked like this.
Line 5: Line 5:
Here's one that only works for whitespace. It relies on the fact that `read` strips all leading and trailing whitespace when `IFS` isn't set: For simple variables, you can trim whitespace (or other characters) using this trick:
Line 7: Line 8:
   # POSIX, but fails if the variable contains newlines
   read -r var << EOF
   $var
   EOF
# POSIX
junk=${var%%[! ]*} # remove all but leading spaces
var=${var#"$junk"} # remove leading spaces from original string

junk=${var##*[! ]} # remove all but trailing spaces
var=${var%"$junk"} # remove trailing spaces from original string
}}}

Bash can do the same thing, but without the need for a throw-away variable, by using [[glob|extglob]]'s more advanced pattern matching:

{{{
# Bash
shopt -s extglob
var=${var##*( )} # trim the left
var=${var%%*( )} # trim the right
}}}

Here's one that only works for whitespace. It relies on the fact that `read` strips all leading and trailing whitespace (tab or space character) when `IFS` isn't set:

{{{
# POSIX, but fails if the variable contains newlines
read -r var << EOF
$var
EOF
Line 14: Line 35:
Line 15: Line 37:
   # Bash
   read -rd '' x <<< "$x"
# Bash
read -rd '' x <<< "$x"
Line 18: Line 40:
Using an empty string as a delimiter means the read consumes the whole string, as NUL is used. (Remember: BASH only does C-string variables.) This is entirely safe for any text, including newlines.
Using an empty string as a delimiter means the read consumes the whole string, as NUL is used. (Remember: BASH only does C-string variables.) This is entirely safe for any text, including newlines (which will also be stripped from the beginning and end of the variable with the default value of IFS).
Line 21: Line 44:
Line 22: Line 46:
   # Bash
   shopt -s extglob
   x=${x##+([[:space:]])} x=${x%%+([[:space:]])}
   shopt -u extglob
}}}
This solution isn't restricted to whitespace like the first few were. You can remove leading zeroes as well:
{{{
   # Bash
   shopt -s extglob
   x=${x##+(0)}
# Bash
shopt -s extglob
x=${x##+([[:space:]])} x=${x%%+([[:space:]])}
Line 34: Line 51:
(where `[[:space:]]` includes space, tab and all other horizontal and vertical spacing characters, the list of which varies with the current [[locale]]).
Line 35: Line 54:
Line 36: Line 56:
   # ksh
   x=${x##+([[:space:]])} x=${x%%+([[:space:]])}
# ksh
x=${x##+([[:space:]])} x=${x%%+([[:space:]])}
}}}

This solution isn't restricted to whitespace like the first few were. You can remove leading zeroes as well:

{{{
# Bash
shopt -s extglob
x=${x##+(0)}
}}}

Another way to remove leading zeroes from a number in bash is to treat it as a decimal integer, in a [[ArithmeticExpression|math context]]:

{{{
# Bash
x=$((10#$x))
Line 41: Line 76:
Line 42: Line 78:
   # POSIX
   while true; do
     case "$var" in
    0*) var=${var#0};;
       *) break;;
     esac
   done
# POSIX
while true; do
  case "$var" in
    0*) var=${var#0};;
    *) break;;
  esac
done
Line 51: Line 87:
Or this parameter expansion trick (covered in more detail in [[BashFAQ/100|FAQ #100]]):

{{{
# POSIX
zeroes=${var%%[!0]*}
var=${var#"$zeroes"}
}}}

Or this mathematical trick:

{{{
# POSIX
a=1$var
b=2$var
var=$((2*a - b))
# This may overflow if $var is very large.
}}}

It should be noted that all of the tricks for removing leading zeroes will '''fail''' if the input value has a sign (`-` or `+`). If you're dealing with potentially signed numeric inputs and need to remove leading zeros to avoid them being interpreted as octal, please see [[ArithmeticExpression]].
Line 52: Line 108:
Line 53: Line 110:
   # POSIX, suppress the trailing and leading whitespace on every line
   x=$(echo "$x" | sed -e 's/^[[:space:]]*//' -e 's/[[:space:]]*$//')
# POSIX, suppress the trailing and leading whitespace on every line
x=$(printf '%s\n' "$x" | sed -e 's/^[[:space:]]*//' -e 's/[[:space:]]*$//')
Line 56: Line 113:
Solutions based on external programs like sed are well suited to trimming large files, rather than shell variables.
Solutions based on external programs like sed are better suited to trimming large files, rather than shell variables.

How can I trim leading/trailing white space from one of my variables?

There are a few ways to do this. Some involve special tricks that only work with whitespace. Others are more general, and can be used to strip leading zeroes, etc.

For simple variables, you can trim whitespace (or other characters) using this trick:

# POSIX
junk=${var%%[! ]*}   # remove all but leading spaces
var=${var#"$junk"}   # remove leading spaces from original string

junk=${var##*[! ]}   # remove all but trailing spaces
var=${var%"$junk"}   # remove trailing spaces from original string

Bash can do the same thing, but without the need for a throw-away variable, by using extglob's more advanced pattern matching:

# Bash
shopt -s extglob
var=${var##*( )}   # trim the left
var=${var%%*( )}   # trim the right

Here's one that only works for whitespace. It relies on the fact that read strips all leading and trailing whitespace (tab or space character) when IFS isn't set:

# POSIX, but fails if the variable contains newlines
read -r var << EOF
$var
EOF

Bash can do something similar with a "here string":

# Bash
read  -rd '' x <<< "$x"

Using an empty string as a delimiter means the read consumes the whole string, as NUL is used. (Remember: BASH only does C-string variables.) This is entirely safe for any text, including newlines (which will also be stripped from the beginning and end of the variable with the default value of IFS).

Here's a solution using extglob together with parameter expansion:

# Bash
shopt -s extglob
x=${x##+([[:space:]])} x=${x%%+([[:space:]])}

(where [[:space:]] includes space, tab and all other horizontal and vertical spacing characters, the list of which varies with the current locale).

This also works in KornShell, without needing the explicit extglob setting:

# ksh
x=${x##+([[:space:]])} x=${x%%+([[:space:]])}

This solution isn't restricted to whitespace like the first few were. You can remove leading zeroes as well:

# Bash
shopt -s extglob
x=${x##+(0)}

Another way to remove leading zeroes from a number in bash is to treat it as a decimal integer, in a math context:

# Bash
x=$((10#$x))

If you need to remove leading zeroes in a POSIX shell, you can use a loop:

# POSIX
while true; do
  case "$var" in
    0*) var=${var#0};;
    *)  break;;
  esac
done

Or this parameter expansion trick (covered in more detail in FAQ #100):

# POSIX
zeroes=${var%%[!0]*}
var=${var#"$zeroes"}

Or this mathematical trick:

# POSIX
a=1$var
b=2$var
var=$((2*a - b))
# This may overflow if $var is very large.

It should be noted that all of the tricks for removing leading zeroes will fail if the input value has a sign (- or +). If you're dealing with potentially signed numeric inputs and need to remove leading zeros to avoid them being interpreted as octal, please see ArithmeticExpression.

There are many, many other ways to do this, using sed for instance:

# POSIX, suppress the trailing and leading whitespace on every line
x=$(printf '%s\n' "$x" | sed -e 's/^[[:space:]]*//' -e 's/[[:space:]]*$//')

Solutions based on external programs like sed are better suited to trimming large files, rather than shell variables.

BashFAQ/067 (last edited 2025-07-19 12:59:21 by GreyCat)