17

In the bash shell, we can define a function f with

f(){ echo Hello; }

and then redeclare/override it, without any error or warning messages, with

f(){ echo Bye; }

I believe there is a way to protect functions from being overridden in this way.

2
  • 2
    the same as with variables, with typeset -r: typeset -rf f.
    – user313992
    Sep 26, 2019 at 7:25
  • 3
    or readonly -f f
    – user313992
    Sep 26, 2019 at 7:26

2 Answers 2

33

You may declare a function foo as a read-only function using readonly -f foo or declare -g -r -f foo (readonly is equivalent to declare -g -r). It's the -f option to these built-in utilities that makes them act on foo as the name of a function, rather than on the variable foo.

$ foo () { echo Hello; }
$ readonly -f foo
$ foo () { echo Bye; }
bash: foo: readonly function
$ unset -f foo
bash: unset: foo: cannot unset: readonly function
$ foo
Hello

As you can see, making the function read-only not only protects it from getting overridden, but also protects it from being unset (removed completely).


Currently (as of bash-5.0.11), trying to modify a read-only function would not terminate the shell if one is using the errexit shell option (set -e). Chet, the bash maintainer, says that this is an oversight and that it will be changed with the next release.

Update: This was fixed during October 2019 for bash-5.1-alpha, so any bash release 5.1 or later would exit properly if an attempt to modify a read-only function is made while the errexit shell option is active.

7
  • Attempt to override function produces message bash: f: readonly function and non-zero status code, but does not exit if errexit option enabled.
    – kyb
    Sep 27, 2019 at 9:55
  • @kyb I noticed this as well. I'm not certain it's a bug in bash, but I will ask on one of the bash mailing lists to be sure.
    – Kusalananda
    Sep 27, 2019 at 10:03
  • good, please update your answer when you will be sure about this behavior.
    – kyb
    Sep 27, 2019 at 14:19
  • 1
    @kyb Both Stephane Chazelas and Greg Wooledge weighed in on that question, both with plausible explanations. Stephane suggests that bash only exits when set -e is in effect when POSIX requires it to (and readonly -f is not POSIX). Greg points out that the bash manual never mentions "failure in function declaration" as reason for errexit to trigger an exit (unless a function declaration counts as a compound command, which he's pretty sure it does not). The thread is ongoing here: lists.gnu.org/archive/html/help-bash/2019-09/msg00039.html
    – Kusalananda
    Sep 27, 2019 at 20:54
  • @kyb I'm also noticing that you never say anything about errexit or set -e in your question.
    – Kusalananda
    Sep 27, 2019 at 20:58
1

Little remark to @Kusalananda's answer. According to what bash maintainer said that changing a read-only function shall trigger the termination of the shell when using set -e.

I'm using Ubuntu 20.10 with a much newer bash version. Unfortunately it seems to be broken.

$ bash --version
GNU bash, version 5.0.17(1)-release (x86_64-pc-linux-gnu)

test.sh

#!/usr/bin/env bash

set -e

test() {
    echo "I'm test() function"
}
readonly -f test

test

test() { # should exit here
    echo "I'm test() function (duplicated)"
}
test

Output

$ chmod +x test.sh; ./test.sh
I'm test() function
./test.sh: line 14: test: readonly function
I'm test() function

I've tested this script inside a docker container using latest bash version and it works as expected.

GNU bash, version 5.1.8(1)-release (x86_64-pc-linux-musl)
1
  • Thank you for updating this thread
    – kyb
    May 17, 2021 at 9:56

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .