Bash Tip - Beware of spaces

Everyone knows that filenames and variables can contain spaces, but when it comes to writing a shell script most of the shell developers seem eager to forget that fact and write scripts that do not safely handle filenames containing spaces.

I can't count the numbers of time I saw people makeing the following mistake when writing their scripts:

fred$ find ./documents -name \*.txt | xargs grep "^Section"

In this example, if the command find returns 3 files a.txt, b b.txt c.txt, grep will search in 4 files: The file a.txt, b, b.txt and c.txt, and will return an error on 2 files that do not exist.

To make that command handle the files containing spaces correctly write it as follows:

fred$ find ./documents -name \*.txt -print0 | grep -0 "^Section"

If you don't want to use the xargs, the following command will also work. (The + option is only on Linux)

fred$ find ./documents -name \*.txt -exec grep "Section" {} +

When you are using a variable or passing it to a function put that variable between quotes.

if [ $filename = "foo bar" ];      # Fail
if [ "$filename" = "foo bar" ];    # Good

example() {
  echo "$1"
  echo "$2"
}
$ a="a"
$ b="b b"
$ example $a $b
a
b
$ example "$a" "$b"
a
b b

Always use the positional parameters between quotes. "$@" is equivalent to "$1" "$2"

print_args() {
  for i in $@; do
    echo "$i"
  done
}
# This will print
print_args "hello" "the world"
hello
the
world

print_args() {
  for i in "$@"; do
    echo "$i"
  done
}
# This will print
print_args "hello" "the world"
hello
the world

For more information see on Positional Parameters.


Comments !