Home > Back-end >  Weird behavior of bash function definitions inside if statements with the foo(){} syntax
Weird behavior of bash function definitions inside if statements with the foo(){} syntax

Time:12-22

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?

CodePudding user response:

  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.

CodePudding user response:

I'm just adding the reference, as the accepted answer (together with the first comment) is right.
From bash man page:

       The  rules  concerning  the  definition and use of aliases are somewhat
       confusing.  Bash always reads at least one complete line of input,  and
       all  lines that make up a compound command, before executing any of the
       commands on that line or the compound command.   Aliases  are  expanded
       when  a  command is read, not when it is executed.  Therefore, an alias
       definition appearing on the same line as another command does not  take
       effect  until  the  next line of input is read.  The commands following
       the alias definition on that line are not affected by  the  new  alias.
       This  behavior  is  also an issue when functions are executed.  Aliases
       are expanded when a function definition is read, not when the  function
       is  executed,  because a function definition is itself a command.  As a
       consequence, aliases defined in a function are not available until  af‐
       ter  that  function  is executed.  To be safe, always put alias defini‐
       tions on a separate line, and do not use alias in compound commands.

The devil is in the details (of the f#*@!n' manual).

  • Related