Search code examples
bashfunctionsyntax-erroralias

Weird behavior of bash function definitions inside if statements with the foo(){} syntax


Let's start with a code that works

$ cat foo1
#!/bin/bash


foo() { 
    echo "I'm here";
}
foo # prints: I'm here

$ ./foo1
I'm here
$ 

so far so good.

Now let's introduce a syntax error

$ cat foo2
#!/bin/bash -i

alias foo="echo I am an alias"
foo() { 
    echo "I'm here";
}
foo # isn't reached

$ ./foo2
bash: ./foo2: line 4: syntax error near unexpected token `('
bash: ./foo2: line 4: `foo() { '
$

woops! let's fix it by unaliasing foo.

$ cat foo3
#!/bin/bash -i

alias foo="echo I am an alias"
unalias foo
foo() {
    echo "I'm here";
}
foo # prints:

$ ./foo3
I'm here
$

what happens if we add an if condition?

$ cat foo4
#!/bin/bash -i

alias foo="echo I am an alias"
if true
then
    unalias foo
    foo() {
        echo "I'm here";
    }
fi
foo # prints:

$ ./foo4
bash: ./foo4: line 7: syntax error near unexpected token `('
bash: ./foo4: line 7: `    foo() { '
$

Why? why is it failing inside an if condition, but used to work without the if condition?

what happens if we use the function foo{} syntax instead of foo(){}?

$ cat foo5
#!/bin/bash -i

alias foo="echo I am an alias"
if true
then
    unalias foo
    function foo {
        echo "I'm here";
    }
fi
foo # prints:

$ ./foo5
I'm here
$

It works now?

Question: why do foo2 and foo4 break?


Solution

    1. Because the alias happens first, then the function definition turns into this (after bash substitutes the alias:

      echo I am an alias() { 
          echo "I'm here";
      }
      

      and that's apparently a syntax error.

    2. Aliases are only substituted on the first word of a command. When you use the function keyword to define the function, then you're avoiding the possibility of alias expansion.

    Ths is probably one of the reasons why aliases are turned off by default in non-interactive shells.