[Top][All Lists]

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Removing a function's function attribute makes `declare` not know it's a

From: Great Big Dot
Subject: Removing a function's function attribute makes `declare` not know it's a function (kind of)
Date: Wed, 21 Nov 2018 23:02:16 -0500

Configuration Information [Automatically generated, do not change]:
Machine: x86_64
OS: linux-gnu
Compiler: gcc
Compilation CFLAGS:  -DPROGRAM='bash' -DCONF_HOSTTYPE='x86_64'
-DCONF_OSTYPE='linux-gnu' -DCONF_MACHTYPE='x86_64-unknown-linux-gnu'
-DCONF_VENDOR='unknown' -DLOCALEDIR='/usr/share/locale' -DPACKAGE='bash'
-DSHELL -DHAVE_CONFIG_H   -I.  -I. -I./include -I./lib  -D_FORTIFY_SOURCE=2
-march=x86-64 -mtune=generic -O2 -pipe -fstack-protector-strong -fno-plt
-DSTANDARD_UTILS_PATH='/usr/bin' -DSYS_BASHRC='/etc/bash.bashrc'
-Wno-parentheses -Wno-format-security
uname output: Linux ArchBox0 4.19.2-arch1-1-ARCH #1 SMP PREEMPT Tue Nov 13
21:16:19 UTC 2018 x86_64 GNU/Linux
Machine Type: x86_64-unknown-linux-gnu

Bash Version: 4.4
Patch Level: 23
Release Status: release

    The manual's section on `declare` (aka `typeset`) states that you can
negate any attribute except for "-r" and "-a"  by replacing "-" with "+".
Aside from the fact that this appears to mistakenly leave out associative
arrays ("-A"), this leaves one to wonder what happens if you try to negate
the function attribute. At first glance, this seems impossible, since a
(non-option) argument to `declare` is assumed to be a variable, and only
gets considered a function if you include the "-f" (or "-F") option. But,
if you include *both* "-f" and "+f", something unusual happens. First the
setup and demonstration of `declare`'s usual behavior:

    $ func () { echo 'hello world'; }
    $ declare -p -- func
    bash: declare: func: not found
    $ declare -pF -- func
    declare -f func
    $ declare -pf -- func
    func ()
        echo 'hello world'

If we try to remove func's function attribute by just saying "declare +f --
func", `declare` (as usual) assumes we mean the *variable *"func", and
nothing of interest happens. It's equivalent to "declare -- func". But what
if we include "-f" to state we're talking about functions and not
variables, yet include "+f" to try to turn it off?

    $ declare -f +f -- func         # Expectation: Error message or no-op.
    $ func                          #
    hello world                     # So nothing changed, right? Wrong.
    $ declare -p -- func            #
    bash: declare: func: not found  # Again as expected. But...
    $ declare -pF -- func           #
    declare -- func                 # The "-f" attribute is missing.
    $ declare -pf -- func           #
    declare -- func="       "       # A tab character? What the heck??
Where did that come from?

Make no mistake, the function is still a function. Executing it works the
same as before, and attempting to expand it as a parameter fails just as
before. In almost all respects, the line `declare -f +f -- func` does
nothing. Yet `declare` has been tricked into an inconsistent view of the
world! Namely, it appears to believe the following things simultaneously:
    *1.* There is no variable named "func".
    *2.* There is a function named "func".
    *3.* This function does NOT have the "-f" attribute. (???)
    *4.* This function has a variable definition, not a function
definition. (???)
    *5.* The value of this variable definition is a single tab character.
Again, `declare`'s vision of the world appears to have no basis in reality.
In particular, expanding "$func" does not yield a tab. Neither the order
nor the case of the "f"-options on the problematic line appear to have any

Few more random observations:

    $ declare -F -- func        #
    func                        # Same as normal.

    $ declare -f -- func        #
    func ()                     # }
    {                           # } Same as normal again.
        echo 'hello world'      # } Has `declare` regained sanity?
(Spoiler: no)
    }                           # }

    # (In the below, irrelevant lines have been removed.)
    $ declare                   #
    func                        # I'm not sure if this is ever a legitimate
output line for a bare `declare`.

    $ declare -f                # Nothing. In particular, different from
`declare -f -- func`.
    $ declare -F                # Again nothing, again different from
`declare -F -- func`.

    $ declare -fp               #
    declare -- func="        "  # Identical wrong answer as `declare -fp --

    $ declare -Fp               #
    declare -- func             # Ditto.

So, we can add these two to the list of things `declare` believes about
    *6.* The function `func` has a function definition.
    *7.* The function (possibly variable?) named "func" exists, but has no
definition. (???)
    *8.* There is no function named "func". (???)

What is going on here?

    $ func () { echo 'hello, world'; }    # Setup.
    $ declare -f +f -- func               # The problem.
    $ declare -pf -- func                 #
    declare -- func="        "            # Now `declare` believes
nonsensical things like this.

N/A. This is just an edge case that would never actually be used. If
anything, this is the expected behavior:

    expected () { printf -- 'bash: declare: %s: inconsistent flags or
something.' "$1" 1>&2; return 1; }

So, just replace any occurrences of the problematic command with calls to
the above, and you're all set! ;)

reply via email to

[Prev in Thread] Current Thread [Next in Thread]