Search code examples
macosbashshelldefaulthomebrew

How can I get iTerm to use the newer version of bash that brew shows? Change a user's shell on OSX


When I do the brew upgradeI see I do have the newer version. How can I use it?

$ bash -version
GNU bash, version 3.2.51(1)-release (x86_64-apple-darwin13)
Copyright (C) 2007 Free Software Foundation, Inc.
$ brew upgrade bash
Error: bash-4.2.45 already installed
$ which bash
/bin/bash

I do see I have

/usr/local/Cellar/bash/4.2.45/bin

but when i do

$ /usr/local/Cellar/bash/4.2.45/bin/bash

I am still in

$ bash -version
GNU bash, version 3.2.51(1)-release (x86_64-apple-darwin13)
Copyright (C) 2007 Free Software Foundation, Inc.
08:06:45 mdurrant w89123148q1 /usr/local/Cellar/bash/4.2.45/bin master

The contents of /etc/shells are:

/usr/local/Cellar/bash/4.2.45/bin/bash  # (I added this)
/usr/local/bin/bash
/bin/bash
/bin/csh
/bin/ksh
/bin/sh
/bin/tcsh
/bin/zsh

chsh didn't seem to do what I hoped:

$ chsh -s /usr/local/Cellar/bash/4.2.45/bin/bash
Changing shell for mdurrant.
Password for mdurrant:
chsh: /usr/local/Cellar/bash/4.2.45/bin/bash: non-standard shell
$ bash --version
GNU bash, version 3.2.51(1)-release (x86_64-apple-darwin13)
Copyright (C) 2007 Free Software Foundation, Inc.

I have the file here:

$ l /usr/local/Cellar/bash/4.2.45/bin/bash
-r-xr-xr-x  1 mdurrant  admin  699688 Apr 14 19:54 /usr/local/Cellar/bash/4.2.45/bin/bash*

I've yet to actually see the new bash version for anyway that I try interactively to invoke it.

$ echo $BASH_VERSION shows

3.2.51(1)-release

I tried using dscl and did

> change Local/Default/Users/mdurrant UserShell /bin/bash /usr/local/Cellar/bash/4.2.45/bin/bash

but got

<main> attribute status: eDSAttributeNotFound
<dscl_cmd> DS Error: -14134 (eDSAttributeNotFound)

and now list shows

> UserShell: /usr/local/Cellar/bash/4.2.45/bin/bash

Solution

  • bash --version (or bash -version) will NOT report the CURRENT shell's version, but the version of the bash executable that comes FIRST IN THE $PATH.

    [Note: OSX 10.10 (Yosemite) is the first OSX version where /usr/local/bin is placed BEFORE system paths such as /bin in the $PATH. Up to 10.9, system paths came first. Thus, at the time the OP asked his question, bash --version reported the SYSTEM's bash's version (/bin/bash), not the Homebrew-installed version (/usr/local/bin/bash)]

    If you want to know the current Bash shell's version, use:

    echo $BASH_VERSION
    

    In other words: your shell may well have been changed successfully - your test was flawed.


    You can use chsh to change the current user's shell, as follows:

    [Update: Switched to using /usr/local/bin/bash and later "$(brew --prefix)/bin" (to account for the fact that on M1 Macs and above the Homebrew root dir. is /opt/homewbrew rather than /usr/local) rather than a specific, versioned path in $(brew --prefix)/Cellar/bash/<version>/bin/bash, as Homebrew will automatically keep the symlink at $(brew --prefix)/bin/bash pointed to the most recent installed version. Tip of the hat to @drevicko.]

    # Determine the full path of the new shell.
    newShell="$(brew --prefix)/bin/bash"
    # Add the full path to the list of allowed shells - SUDO REQUIRED
    sudo bash -c "echo \"$newShell\" >> /etc/shells"
    # Then change to the new shell.
    chsh -s "$newShell"
    

    Note that you'll be prompted for your password.
    Any terminal tab/window you create from that point on will already use the new shell.

    Bonus tip from @bmike: If you want to replace the current shell instance with an instance of the new shell right away, run:

    exec su - $USER  # instantly replaces current shell with an instance of the new shell
    

    Note that you'll be prompted for your password again.


    Alternatively, use dscl - the OSX Directory Services CLI - to change the current user's shell; this is more cumbersome, however.

    To examine the current user's shell, use:

    dscl . -read /Users/$USER UserShell  # e.g. (default): 'UserShell: /bin/bash'
    

    or, more simply, echo $SHELL, which outputs only the file path (e.g., /bin/bash).

    To change the current user's shell to, e.g., $(brew --prefix)/bin/bash, use:

    # SUDO REQUIRED
    sudo dscl . -change /Users/$USER UserShell /bin/bash "$(brew --prefix)/bin/bash"
    

    Note:

    • the penultimate (second-to-last) argument must be the value currently in effect.
    • it is NOT necessary for the new value to be contained in /etc/shells for interactive use, but the comments in /etc/shells state Ftpd will not allow users to connect who are not using one of these shells.
    • simply quit and restart Terminal.app (or iTerm.app) for the change to take effect - verify the new shell with echo $BASH_VERSION - a reboot is NOT required.

    Explanation of errors encountered by the OP:

    • chsh: /usr/local/Cellar/bash/4.2.45/bin/bash: non-standard shell implies that /usr/local/Cellar/bash/4.2.45/bin/bash was not - not yet, or not in this exact form - listed in /etc/shells.
    • <main> attribute status: eDSAttributeNotFound: this dscl error occurs when the penultimate (next-to-last) argument specified for the -change command does not match the current attribute value - it is an - admittedly strange - requirement that an attribute's current value be specified in order to change it.

    While the question suggests that both conditions were met, I suspect that they weren't met at the right times, due to experimentation.