Skip to content

Instantly share code, notes, and snippets.

@RulerOf
Last active May 3, 2023 18:18
Show Gist options
  • Save RulerOf/f41259f493b965c9354c2564d85b11ce to your computer and use it in GitHub Desktop.
Save RulerOf/f41259f493b965c9354c2564d85b11ce to your computer and use it in GitHub Desktop.
Using a different shell without running `chsh`

Problem

I wanted to create a jumpbox where the default shell was zsh, but I couldn't actually change the default shell of the users that would be connecting to the box. I also wanted to manage some symlinks in the user profile dynamically with Dotbot.

My initial idea was to add a script to /etc/profile.d that would just dump users into /bin/zsh, but this had several different problems, including the all-important question of "But what if I want to run Bash on purpose?"

Solution

Through a little bit of trial and error, I settled on this script located at /etc/profile.d/dotbot.sh

# Only run under bash
if [[ $0 == *"bash" ]]; then
  # Only for interactive sessions
  if [[ $- == *i* ]]; then
    # And only for the login session
    if shopt -q login_shell; then
      if command -v /usr/local/bin/dotbot > /dev/null; then
        /usr/local/bin/dotbot -c /srv/dotfiles/dotbot.conf.yaml -q
        # Enter zsh
        zsh; exit $?
      else
        >&2 echo "Error: Cannot configure user profile, unable to find Dotbot"
      fi
    fi
  fi
fi

Explanations

A bunch of nested ifs are always fun:

Only run under bash

# Only run under bash
if [[ $0 == *"bash" ]]; then

Early on, I thought I might actually switch the default shell at some point, so this was borne out of a desire for compatibility. The test is written as *"bash" because the login shell coming from our LDAP is /bin/bash, whereas my testing of $0 indicated it's just bash. This was so they'd both work.

Only for interactive sessions

# Only for interactive sessions
if [[ $- == *i* ]]; then

Without this step, things like rsync and scp would break.

And only for the login session

# And only for the login session
if shopt -q login_shell; then

What if you actually need bash though? This check will always be false except for the top-level shell, so users who are currently in a zsh session can run bash without the script dumping them right back into zsh.

Check for dotbot and run zsh

if command -v /usr/local/bin/dotbot > /dev/null; then
  /usr/local/bin/dotbot -c /srv/dotfiles/dotbot.conf.yaml -q
  # Enter zsh
  zsh; exit $?
else
  >&2 echo "Error: Cannot configure user profile, unable to find Dotbot"
fi

Check to make sure that dotbot is installed, then start zsh. The zsh; exit $? is there to pass exit codes up, but also to ensure that exit/logout in the zsh shell actually disconnect the user coming in via SSH. Otherwise they'd exit zsh and drop into the bash shell that's hosting it.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment