Safely Manage Valid Login Shells in /etc/shells
You will inspect the valid-shell list, check that a proposed entry is a real executable, and change one account's login shell without guessing what the file controls. You will also have a recovery path if an entry is wrong. Allow about ten minutes for inspection, or fifteen to twenty minutes if you need to make and verify a change.
The route
Jump straight to the step you need, or tick off Done means at the end.
This guide uses the local Linux man-pages 6.7 package and shadow-utils 4.13. The examples assume a normal account with sudo available when a system file or another user's account must be changed. Inspection is unprivileged. Editing /etc/shells and changing another account's shell require elevated privileges.
1. Inspect the file before changing anything
/etc/shells is a text file containing full pathnames of valid login shells. It is consulted by chsh and can also be queried by other programs. It is not a list of every executable that happens to be a shell, and it does not select your current shell by itself.
$ command -v bash
/usr/bin/bash
$ sed -n '1,160p' /etc/shells
# /etc/shells: valid login shells
/bin/sh
/usr/bin/sh
/bin/bash
/usr/bin/bash
/usr/bin/rbash
/usr/bin/rbash
/usr/bin/dash
/usr/bin/screen
/usr/bin/tmux
/bin/false
Your output will differ. The duplicate-looking paths above are separate names, and /bin and /usr/bin may be linked or mounted differently on another system. Do not copy this list blindly. Check the paths that exist on your host.
Checkpoint: save a root-owned backup before any edit. This command only reads the file and creates a backup in the same directory, so treat the backup path as part of your recovery plan:
$ sudo cp --preserve=mode,ownership /etc/shells /etc/shells.bak
$ sudo ls -l /etc/shells /etc/shells.bak
2. Verify a proposed shell path
Choose the exact pathname you intend to use. Check that it is executable and that it reports a sensible identity. These checks do not add it to the valid-shell list.
$ NEW_SHELL=/usr/bin/bash
$ test -x "$NEW_SHELL" && echo "executable: $NEW_SHELL"
executable: /usr/bin/bash
$ "$NEW_SHELL" --version | head -n 1
GNU bash, version 5.2.21(1)-release (x86_64-pc-linux-gnu)
Replace the version output with the output from your machine. Do not use a path copied from a different host, a temporary test program, or a wrapper whose behaviour you have not inspected. A valid entry points to a program that can serve as an account's initial login command. /bin/false is commonly listed to mark accounts that must not receive an interactive login; listing it does not make it an interactive shell.
3. Add the path only when you mean to change policy
Adding a line changes how programs that consult /etc/shells classify accounts. FTP daemons traditionally use the file to reject users whose shell is not listed. PAM configurations using pam_shells.so can also deny access when the account's shell is absent. This is a security-sensitive configuration change, so do not add a path merely to make a command stop complaining.
First confirm that the exact line is not already present:
$ grep -Fx -- "$NEW_SHELL" /etc/shells > /dev/null
$ printf 'grep status: %s\n' "$?"
grep status: 0
Status 0 means it is already listed. If the status is 1, edit the file as root and add one full pathname on its own line. Use sudoedit so the editor runs as your account while the saved file is written with the correct privilege:
$ sudoedit /etc/shells
# Add this exact line if it is absent:
/usr/bin/bash
Do not remove existing entries to tidy the file until you know which services depend on them. Do not put a command, option, environment assignment, or relative path on the line. Save the edit, then verify the exact entry and file ownership:
$ grep -Fx -- "$NEW_SHELL" /etc/shells
/usr/bin/bash
$ stat -c '%U:%G %a %n' /etc/shells
root:root 644 /etc/shells
The mode and ownership shown are typical, not a universal requirement. The important checks are that the new line is exact and that the file was not accidentally made writable by ordinary users.
4. Check the account's current shell
The account record stores its login shell separately. Inspect it before changing anything:
$ getent passwd "$USER" | awk -F: '{print "account: " $1 "\nlogin shell: " $7}'
account: andy
login shell: /bin/bash
The seventh field is the pathname used for the account's login shell. Compare it with /etc/shells, but do not confuse a listed path with a running shell. Existing sessions do not change when you edit either file.
5. Change your own login shell with chsh
For your own account, use chsh without sudo. The installed command accepts the new pathname with -s or --shell and checks that a normal user's choice is listed in /etc/shells:
$ chsh -s "$NEW_SHELL"
$ getent passwd "$USER" | awk -F: '{print $1 ": " $7}'
andy: /usr/bin/bash
A successful chsh normally produces no useful output, so the second command is the checkpoint. Start a new login session before expecting the new shell to run. Closing and reopening a terminal emulator may only create a non-login shell, depending on its settings.
To change another account, an administrator can specify its login name:
$ sudo chsh -s /usr/bin/bash ACCOUNT_NAME
$ getent passwd ACCOUNT_NAME | awk -F: '{print $1 ": " $7}'
Replace ACCOUNT_NAME with the intended account. This alters account state and can strand a user if the path is wrong or the program exits immediately. Confirm the pathname first and tell the user what will change.
6. Recover from a bad entry or unwanted shell
Stop before deleting the backup. If the new shell is rejected, inspect the exact spelling, executable bit, and list membership. A path can exist but still be unsuitable, and a shell can be valid for chsh while a service applies additional policy.
If you need to restore the previous valid-shell list, this is a deliberate overwrite of a system file. Check the backup first, then restore it:
$ sudo test -s /etc/shells.bak && echo 'backup exists and is non-empty'
backup exists and is non-empty
$ sudo cp --preserve=mode,ownership /etc/shells.bak /etc/shells
$ grep -Fx -- "$NEW_SHELL" /etc/shells || echo 'new entry is no longer listed'
If an account's shell was changed and you need to undo that change, run chsh -s again with the previously recorded, valid pathname. Do not delete /etc/shells.bak until you have tested the affected login and services. Removing a backup with rm is irreversible.
Done means
/etc/shellscontains only deliberate, absolute pathnames to programs you checked.- The file's exact entries and ownership were verified after any edit.
- Your account's stored shell was inspected separately from the current session.
- Any
chshchange was made for the intended account and verified throughgetent passwd. - A readable backup remains until the new login and dependent services have been tested.