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 | xargs 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.