Skip to content

Bash tips and tricks

Jean Prunneaux edited this page Apr 16, 2018 · 15 revisions

Introduction

Develop in BASH can really be a nightmare if you are not aware of some details about it. Even if libbash.sh helps you a lot 😃, here are some tips and tricks you should know.

To go further, see the amazing tool Shellcheck.

Table of contents

  • Spaces and quotes
    • Quotes in paths
    • Quotes in arguments
    • Quotes in comparison statements
    • Quotes in variables attribution
    • Quotes in parsing arguments
    • Quotes in arrays
    • Quotes in commands
    • Simple quotes or double quotes?
  • Return codes
    • The last command result
    • Function returns
    • return command VS exit command
  • Arrays (coming soon...)
    • Syntax
  • Running commands
    • Commands and spaces

Spaces and quotes

You should ALWAYS put double quotes around your variables! Let's see why:

Quotes in paths

If you make any operation on paths and files, put ALWAYS double quotes around them, or paths with spaces will fail to open. Example:

$ file="/path/file with spaces.txt"
$ cat $file
cat: /path/file does not exists!
cat: with does not exists!
cat: spaces.txt does not exists!

You should have done:

cat "$file"

Quotes in arguments

Consider this example:

mycommand() {
    first=$1
    second=$2
    ...
}
arg1="argument with spaces"
arg2=1234
mycommand $arg1 $arg2

In this case, $first has argument and $second has with. To avoid this, call:

mycommand "$arg1" "$arg2"

Quotes in comparison statements

Consider this example:

spaces="  "
if [ -z $spaces ] ; then ...

In this example, the $spaces variable will be considered empty. So you should put quotes in comparison statements:

if [ -z "$spaces" ] ; then ...

Consider another example:

$ var=""
$ if [ $var == hello ] ; then ...
bash: [: == : unary operator expected

If $var is empty, the if statement will fail with a bash crash (code 2) and will print and error on stderr. With quotes, it will never crash, even if variable is empty:

$ if [ "$var" == hello ] ; then ...

Surprisingly, the case statement does not need quotes:

var="some text"
case $var in ...

Quotes in variables attribution

Variable attribution is a rare case where you don't need quotes. The following example is correct:

var1="variable with spaces"
var2=$var1

But if you cant to concatenate with another string, don't miss the quotes:

var1="variable with spaces"
var2="$var1 and something else"

Quotes in parsing arguments

Consider this example:

mycommand() {
    for arg in $* ; do
        echo $arg
    done
}
arg1="argument with spaces"
arg2=1234
mycommand "$arg1" "$arg2"

It will return:

argument
with
spaces
1234

To avoid that, you have to use "$@" instead of $*:

mycommand() {
    for arg in "$@" ; do
        echo $1
    done
}

Quotes in arrays

Consider this example:

array=("hello world" "this is John")
for a in ${array[@]} ; do
   echo $a
done

This will return:

hello
world
this
is
John

To avoid that, you have to use quotes:

for a in "${array[@]}" ; do
   echo $a
done

Quotes in commands

See chapter Commands and spaces in Running commands section.

Simple quotes or double quotes?

You should prefer double quotes, but it depends what you want to do. While var="some text" and var='some text' does exactly the same, it will not work properly if you include variable names inside simple quotes:

$ var='some text'
# bad call
$ echo '$var with spaces'
$var with spaces
# good call
$ echo "$var with spaces"
some text with spaces

Return codes

The last command result

The last command result code (0-255) may have some unexpected values regarding context:

mycommand               # $? = result of mycommand
var=$(mycommand)        # $? = result of mycommand
local var=$(mycommand)  # $? ALWAYS = 0 because local command is OK
if [ "$var" == "result" ] ; then
   echo OK
fi
# even if var="result", $? ALWAYS = 0 because the if syntax was OK
if [ "$(mycommand)" == "result" ] ; then
   echo OK
fi
# even if mycommand fails, $? ALWAYS = 0 because the if syntax was OK
if false ; then
   echo OK
fi
# even if the if statement will always be false, $? ALWAYS = 0 because the if syntax was OK

Function returns

If you don't call the return command at the end of a function, the function will return the last command result (similar to return $?). See above for more details about last command results.

return command VS exit command

  • return without argument will return the last command result (similar to return $?)
  • exit without argument will return code 0

Arrays (coming soon...)

Syntax

Running commands

Because of the spaces (again!), running commands can fail. See why below.

Commands and spaces

Consider this example:

rsync_command="rsync -e 'ssh -p 2222' myserver:/path /path"
# execute command
$rsync_command

In this example, the command will fail, because the -e option has spaces inside it and bash execute it as:

rsync -e ssh -p 2222 myserver:/path /path

Every time you are running commands from variables, the only way to avoid spaces bugs is to use an array:

rsync_command=(rsync -e 'ssh -p 2222' myserver:/path /path)
# execute command; DO NOT FORGET THE QUOTES!
"${rsync_command[@]}"
Clone this wiki locally