Y. K
Y. K

Reputation: 182

bash's strange behavior on a function named "@"

Today I found a strange behavior in bash.

When you define function named "@" in an interactive shell using this syntax:

$ function @() { echo foo; }

it (of course) defines a function named "@".

However, in specific situations, e.g. in tmux session or in virtual console (Ctrl+Alt+F1), this defines a function named "@()". I couldn't find any difference in these environments (output of echo $- was himBH). Besides, function @ { echo bar; } doesn't have this trap and defines "@" in both situations. I couldn't find any document that says @ is a special symbol in bash.

Does anyone know anything about this? I confirmed these on vanilla Ubuntu 16.04.2.

Upvotes: 2

Views: 121

Answers (2)

pynexj
pynexj

Reputation: 20698

The "problem" is caused by the shell option extglob.

extglob: on

[STEP 100] # echo $BASH_VERSION
4.4.12(1)-release
[STEP 101] # shopt -s extglob 
[STEP 102] # echo @()
@()
[STEP 103] # function @() { shopt extglob; }
[STEP 104] # @()
extglob         on
[STEP 105] # unset -f @()
[STEP 106] # 

When extglob on, I guess Bash's syntax parser would treat @() as a whole (because it looks like a valid extended glob pattern) and pass it to the function command as one single paramter so function @() {} is in the function NAME {} syntax and so @() is the function name.

extglob: off

[STEP 107] # shopt -u extglob 
[STEP 108] # echo @()
bash: syntax error near unexpected token `('
[STEP 109] # function @() { shopt extglob; }
[STEP 110] # @
extglob         off
[STEP 111] #

When extglob off, function @() {} is in the function NAME() {} syntax and so @ is the function name.


Chet's explanation in the bug-bash mailing list:

A shell function name is a WORD, though POSIX mode restricts it to a NAME. It does not undergo any expansions.

When extglob is enabled, @() is part of a WORD, since it's a valid extended glob pattern, and glob patterns can be contained in a WORD. This is one example of the differing parser behavior when extglob is enabled. So there's no problem with defining a function named @(). When extglob is not enabled, @() is not a valid pattern, and the parens are parsed as separate operators. In this case they happen to make sense, and define a function named @.

When you try to execute it, since it's not quoted, it undergoes the normal word expansions, one of which is filename generation. It doesn't match anything, so it's left intact, and the function named @() executes. When nullglob is enabled, the pattern still doesn't match anything, and is removed. This leaves you with the null command, which also executes, and returns a status of 0.

Upvotes: 3

mattmc
mattmc

Reputation: 479

In bash there are two scenarios (that I'm aware of) where the "@" symbol is used. The first is when dealing with parameters:

function mytest() {
    echo $@
}
mytest "param1" "param2" "param3"

The second is when dealing with arrays:

declare myarray=("item1" "item2")
printf "${myarray[@]}\n"

While function @() {} may work as a function name, it should be considered bad practice. Give functions a practical name. Something that tells the user what it's purpose is.

Upvotes: 1

Related Questions