For some it may be a "big gun to kill an ant", but I did it in my free time to practice some things in shell.
Below is my "elegant" solution to change the default shell interactively and with some contingencies to ensure that it is changed according to the user's choice:
#!/usr/bin/env bash
clear_screen() {
sleep 1
printf "\033[2J\033[H"
}
# Clears the terminal screen after a short pause.
# Function to check if the shell is available
# Arguments:
# $1 - The shell to check
# Returns:
# 0 if the shell is available, 1 otherwise
check_shell_available() {
local shell=$1
echo "$_AVAILABLE_SHELLS" | grep -q "$shell"
}
# Checks if the specified shell is available in the list of known shells.
# Function to check if the shell is safe
# Arguments:
# $1 - The shell to check
# Returns:
# 0 if the shell is safe, 1 otherwise
check_shell_safe() {
local shell=$1
# List of allowed shells that i know are safe (sweet yourself with your own list)
local allowed_shells=(
"/bin/sh" "/usr/bin/sh"
"/bin/bash" "/usr/bin/bash"
"/bin/rbash" "/usr/bin/rbash"
"/bin/dash" "/usr/bin/dash"
"/bin/zsh" "/usr/bin/zsh"
"/usr/bin/fish"
"/usr/bin/screen"
"/usr/bin/tcsh"
"/usr/bin/ksh"
"/usr/bin/mksh"
"/usr/bin/lksh"
"/usr/bin/oksh"
"/usr/bin/posh"
"/usr/bin/yash"
"/usr/bin/elvish"
"/usr/bin/xonsh"
)
local forbidden_shells=("/bin/false" "/usr/sbin/nologin")
[[ " ${allowed_shells[*]} " == *" $shell "* ]] && [[ -x $shell ]] && [[ $shell == /* ]] && [[ ! " ${forbidden_shells[*]} " == *" $shell "* ]]
}
# Checks if the specified shell is allowed and safe to use.
# Function to change the user's shell
# Arguments:
# $1 - The shell to change to
change_user_shell() {
local shell=$1
sudo usermod --shell "$shell" "$(id -un)"
}
# Changes the user's shell to the specified shell using the usermod command.
# Function to verify if the shell was changed
# Arguments:
# $1 - The shell to verify
# Returns:
# 0 if the shell was changed, 1 otherwise
verify_shell_change() {
local shell=$1
local current_shell
current_shell=$(grep "^$(id -un):" "$_PASSWD_FILE" | cut -d: -f7)
[ "$current_shell" == "$shell" ]
}
# Verifies if the user's shell was successfully changed.
printf "Starting script...\n"
# Check if the user is in the sudo group
if ! groups | grep -q '\bsudo\b'; then
printf "The user is not in the sudo group.\n"
exit 1
fi
# Check if the dialog command is available
if ! command -v dialog &> /dev/null; then
# Ask the user if they want to install dialog
printf "The dialog command is not available. Do you want to install dialog? (y/n) "
read -r response
if [[ ! "$response" =~ ^[Yy]$ ]]; then
printf "Dialog installation canceled.\nPackage required to continue.\n"
exit 0
fi
if ! sudo apt-get install -y dialog; then
echo "Could not install dialog."
exit 1
fi
clear_screen
fi
# Update the list of available shells, if possible
command -v update-shells &> /dev/null && sudo update-shells
# Updates the list of known shells, if the update-shells command is available.
# Get the list of available shells
_AVAILABLE_SHELLS=$(grep -v '^#' "/etc/shells" | tr '\n' ' ')
# Display the list of available shells for the user to choose
# shellcheck disable=SC2086
_SHELL=$(dialog --menu "Choose the shell you want to use:" 15 50 10 $_AVAILABLE_SHELLS 3>&1 1>&2 2>&3)
# Displays a dialog menu for the user to select the desired shell.
# Check if the shell is available
if ! check_shell_available "$_SHELL"; then
dialog --msgbox "The shell you entered is not available." 10 50
exit 1
fi
# Check if the shell is safe
if ! check_shell_safe "$_SHELL"; then
dialog --msgbox "The shell you entered is not safe." 10 50
exit 1
fi
# Ask the user if they want to perform the operation
dialog --yesno "Do you want to change the shell to $_SHELL?" 10 50
response=$?
if [ $response -ne 0 ]; then
exit 0
fi
_PASSWD_FILE="/etc/passwd"
# Try to change the shell using chsh
chsh -s "$_SHELL"
# Attempts to change the user's shell using the chsh command.
# Verify if the shell was changed
if ! verify_shell_change "$_SHELL"; then
# Try to change the shell using usermod
change_user_shell "$_SHELL"
# Attempts to change the user's shell using the usermod command.
# Verify if the shell was changed
if ! verify_shell_change "$_SHELL"; then
# Try to change the shell directly in the passwd file
_CURRENT_SHELL=$(grep "^$(id -un):" "$_PASSWD_FILE" | cut -d: -f7)
_OLD_LINE=$(grep "$(id -un):x:$(id -u):$(id -g)" "$_PASSWD_FILE" | grep "$(which "$_CURRENT_SHELL")")
_NEW_LINE="${_OLD_LINE//$(which "$_CURRENT_SHELL")/$(which "$_SHELL")}"
sudo sed -i "s|$_OLD_LINE|$_NEW_LINE|" "$_PASSWD_FILE"
# Directly modifies the /etc/passwd file to change the user's shell.
# Verify if the shell was changed
if ! verify_shell_change "$_SHELL"; then
dialog --msgbox "Could not change the shell." 10 50
exit 1
fi
fi
fi
dialog --msgbox "Shell successfully changed to $_SHELL." 10 50
dialog --msgbox "Restart the session to apply the changes." 10 50
clear_screen
exit 0
Feel free to change the trusted list and the methods of changing them or the order in which you try them.
If you have any questions, I'm here to answer them, just ask. (I'm also willing to make edits, if necessary)
Hope you like it!
EDIT: I added more explanatory comments about each method.
chsh, which means you will have to log in again.