唯一权威方式是读取 /etc/shells 文件,该文件由 pam 和 chsh 等机制用于校验登录 shell 合法性;不在其中的路径会被 chsh 或 usermod -s 拒绝;chsh 不带参数时会自动列出其内容,cat /etc/shells 可直接查看,每行一个绝对路径,普通用户可读。

直接读 /etc/shells 是唯一权威方式
系统支持哪些 shell,不是靠猜、不是靠 which 或 ls /bin,而是由 /etc/shells 文件定义的。这个文件是 PAM 和 chsh 等机制校验登录 shell 合法性的依据——不在这个文件里的路径,chsh 会拒绝,usermod -s 也会报错。
执行:cat /etc/shells
- 输出是纯文本,每行一个绝对路径,如
/bin/bash、/usr/bin/zsh、/bin/dash - 普通用户有读权限,无需
sudo - 该文件内容可能被管理员手动编辑,比如添加自编译 shell 路径,但必须确保该路径下程序真实存在且有执行权限
chsh 不带参数也能列出,但本质还是读 /etc/shells
运行 chsh(不加任何选项或参数),它会进入交互式菜单,并自动打印出 /etc/shells 中所有条目供选择。这不是额外功能,只是 chsh 的默认行为。
- 适合快速浏览,尤其在没有 GUI 或
cat不便时(比如某些最小化容器) - 部分精简系统(如 Alpine Linux)可能删掉了
chsh,此时只能靠cat /etc/shells -
chsh -l在部分发行版(如 Debian/Ubuntu)可用,等价于直接输出/etc/shells;但 RHEL/CentOS 默认不支持该选项,会报错“unrecognized option”
别把 $SHELL 或 ps 当成“支持列表”
$SHELL 只是记录你在 /etc/passwd 里配置的默认登录 shell;ps -p $$ 只反映当前进程实际在跑哪个解释器。两者都和“系统支持哪些 shell”完全无关。
- 例如:你用
zsh登录,$SHELL是/bin/zsh,但/etc/shells里可能根本没有这行——说明该 shell 虽然能运行,但不被系统认可为合法登录 shell - 又例如:你手动执行
/opt/myshell,ps能看到它,但如果它没写进/etc/shells,就不能设为登录 shell,也不能通过chsh切换 - 混淆这两者,容易误判环境兼容性,尤其在写 CI 脚本或容器镜像时
注意 /bin/sh 的真实身份
很多人的第一反应是“/bin/sh 就是 Bourne Shell”,但现代 Linux 几乎都不装原始 sh。它通常是 dash(Debian/Ubuntu)或 bash(RHEL/CentOS)的符号链接,行为严格遵循 POSIX。
- 查真实指向:
readlink -f /bin/sh - 验证是否 bash 兼容:
/bin/sh -c 'echo ${BASH_VERSION:-no}'—— 有输出才是真 bash,否则大概率是 dash - 这意味着:即使
/etc/shells里有/bin/sh,也不能默认它支持[[、数组、source别名等 bash 特性











