Search code examples
bashsetposix

`set -o posix` Not Working in Bash 5.0.17 on WSL2 Ubuntu 20.04


As mentioned in the title, the set -o posix option does not appear to be working in GNU/Linux bash 5.0.17 (I'm not sure it's specifically related to WSL2 Ubuntu 20.04 or anything, but noted it in case it is working for others on their machines).

I can turn it on and off:

$ set -o |grep posix
posix        off
$ set -o posix
$ set -o |grep posix
posix        on
$ set -o posix
$ set -o |grep posix
posix        off
$ set -o posix
$ set -o |grep posix
posix        on

but, for example, when on I am able to do the following

$ set -o posix
$ set -o |grep posix
posix        on
$ type cd
cd is a shell builtin
$ cd /
$ ls
bin   dev  home  lib    lib64   lost+found  mnt  proc  run   snap  sys  usr
boot  etc  init  lib32  libx32  media       opt  root  sbin  srv   tmp  var
$ cd() { :; }
$ type cd
cd is a function
cd ()
{
    :
}
$ cd ~
$ ls
bin   dev  home  lib    lib64   lost+found  mnt  proc  run   snap  sys  usr
boot  etc  init  lib32  libx32  media       opt  root  sbin  srv   tmp  var
$ unset -f cd
$ cd ~
$ ls
Desktop  Documents  Downloads  Music  Pictures  Public  Templates  Videos

I am able to override all special builtins (including builtin and type!). Also, I am not root, but just in my user account. Does anyone know what I am doing wrong?

UPDATE:

@Shawn, @oguzismail, and @Dan all give the correct answer below: cd is a regular builtin. I wanted to add some clarification as I think it will be important for learners like me:

@oguzismail correctly points to the section of Classic Shell Scripting that explains that cd is a regular built-in:

For this reason, you can write a function named cd, and the shell will find your function first, since cd is a regular built-in

  • Section 7.9 (pg. 261 in Kindle Edition)

My confusion came from the statement in the summary:

Built-in commands exist either because they change the shell’s internal state and must be built-in (such as cd), or for efficiency (such as test).

  • (Section 7 Summary, pg. 264 in Kindle Edition)

Here, cd is a builtin, but as the author states previously, it is a regular builtin. It has to be a command built into the shell because the command changes the internal state of the shell (i.e. it changes the current/present working directory of the shell), but it can be either a regular or special builtin. As @Dan mentions, the POSIX IEEE Std 1003.1-2017 standard, Section 2.14 defines it as a regular builtin. (For at least one reason why, Section 7.9 of Classic Shell Scripting shows that doing so permits the programmer to customize its behavior.)

Be Warned Though! (NB = Nota Bene): If you do choose to overwrite cd with a user-defined function, use command cd within the function definition where you want to actually change directories. The function command skips looking for functions in the POSIX-defined search order of special built-ins --> functions --> regular built-ins --> external commands on $PATH. Otherwise, if you use cd within your user-defined function cd, you will most likely end up with an infinite recursion loop. (Classic Shell Scripting also covers this point.)


Solution

  • set -o posix works fine:

      $ set -o posix
      $ set () { :; }
    bash: `set': is a special builtin
    

    cd is not a special built in, nor is builtin or type.

    The list of "special builtins" is clearly defined in the posix specification.

    A "special built-in" is distinct from any other command which a shell may or may not implement as a built-in.