一、什么是shell
广义的shell指的是,能够操作应用程序的接口都称为shell,(包括linux和windows的图形界面)
狭义的shell是指,命令行方面的程序,包括zsh,bash,csh,等等
怎样查看当前系统的可用shell呢?
文件/etc/shells 中所列的shell,称为当前系统上安全的shell列表。默认shell如果不是文件/etc/shells中的shell,很可能拒绝用户登入系统。
# [root@localhost ~]# cat /etc/shells /bin/sh /bin/bash /sbin/nologin /usr/bin/sh /usr/bin/bash /usr/sbin/nologin /bin/tcsh /bin/csh
为甚么/etc/shells 文件中的shell列表称为合法的shell列表,这是因为系统某些服务在运行的时候,会去检查用户能够使用的shells,而检查的标准就是根据/etc/shells 文件中的shell列表。
二、bash命令与sh命令的区别
Linux 操作系统缺省的 shell 是Bourne Again shell,它是 Bourne shell 的扩展,简称 Bash,与 Bourne shell 完全向后兼容,并且在Bourne shell 的基础上增加、增强了很多特性。
GNU/Linux 操作系统中的 /bin/sh 本是 bash (Bourne-Again Shell) 的符号链接,但鉴于 bash 过于复杂,有人把 ash 从 NetBSD 移植到 Linux 并更名为 dash (Debian Almquist Shell),并建议将 /bin/sh 指向它,以获得更快的脚本执行速度。Dash Shell 比 Bash Shell 小的多,符合POSIX标准。
debian和Ubuntu中,/bin/sh默认已经指向dash,这是一个不同于bash的shell,它主要是为了执行脚本而出现,而不是交互,它速度更快,但功能相比bash要少很多,语法严格遵守POSIX标准。
三、bash的四种模式
在man bash的INVOCATION一节讲述了bash的四种模式,bash会依据这四种模式而选择加载不同的配置文件,而且加载的顺序也有所不同。
Bash是shell的一种,运行中的Bash有两种属性(状态/模式),一种,是否interactive shell(交互式Shell),另一种,是否login shell(登录Shell)。两种组合成四种模式。
login shell(登入式shell):
定义:A login shell is one whose first character of argument zero is a -, or one started with the --login option.
大概意思是:一个登入式shell,它的第零个参数的第一个字符是 -,或者 它是一个以 --login 选项启动的shell。
解释一下这个定义:
1、第零个参数的第一个字符是 - 的shell是登入式shell
比如: tty1-tty6 终端登入系统(系统默认shell是bash)是登入式shell
tty1-tty6 登入系统后
# dayun@c:~$ echo $0 -bash
第零个参数的第一个字符是 -,所以这是一个登入式shell。
2、以 --login 选项启动的bash是登入式shell
比如:bash --login[-l]
系统登入以后,在当前shell中登入子shell时,加上--login选项,表示登入的这个子shell是登入式shell
此外。除定义外,我们判断这两种模式的方法。
登入式shell与非登入式shell的区别我们可以从字面上理解,登入式shell要求用户输入用户名,密码。包含登入一个shell的全过程。(这个说法不一定严谨准确,比如bash --login[- l] 这种方式就不需要输入用户名密码,因为它登入的是当前shell的子shell,用户名,密码与当前shell相同,所以省去)
登入式shell和非登入式shell的退出机制不同。
非登入式shell,退出时,使用exit命令退出,不能使用logout命令退出
# cluster@c:~$ bash #运行bash命令,进入当前shell的子shell(非登入式shell) cluster@c:~$ logout #运行login命令 bash: logout: not login shell: use `exit' #报错,因为是非登入式shell,不能用login退出 cluster@c:~$ exit #使用exit命令 exit cluster@c:~$ #成功退出
登入式shell,退出时,使用logout命令退出,能够使用exit命令退出,但是此时的exit命令扔是调用logout命令。
# #登入式shell使用logout命令正常退出 cluster@c:~$ bash -l cluster@c:~$ logout cluster@c:~$ #登入式shell使用exit命令,通过调用logout命令,也能退出 cluster@c:~$ bash -l cluster@c:~$ exit logout cluster@c:~$
常见的login shell与no-login shell
tty1-tty6直接登入的shell为login shell。
su -[l] UserName为登入式shell 如果不带有-或-l选项的为no-login shell
ssh UserName@HostName 通过ssh登入shell为登入式shell。ssh UserName@HostName "command"为非登入式shell
bash --login[-l]为登入式shell,没有--login或-l选项的为非登入式shell,以下相同。
su -[l] UserName -c "command"
bash --login[-l] -c "command"
bash -l[--login] script.sh
你以 X window 登陆 Linux 后, 再以 X 的图形化接口启动终端机
interactive shell(交互式shell):
定义:An interactive shell is one started without non-option arguments and without the -c option whose standard input and error are both connected to terminals (as determined by isatty(3)), or one started with the -i option. PS1 is set and $- includes i if bash is interactive, allowing a shell script or a startup file to test this state.
大概意思是:不带有非选项参数,且没有-c选项,它的标准输入与标准输出直接与终端相连的的shell是交互式shell,或者有-i选项的也是交互式shell。交互式shell他的PS1一般被设置,并且变量$-包含i
解释一下这个定义:
1、不带有非选项参数,且没有-c选项,它的标准输入与标准输出直接与终端相连的的shell是交互式shell。
什么是非选项参数,bash /path/to/script.sh 中的/path/to/script.sh就是非选项参数,像-c,-i,-l,--login等都是选项参数。例子中带有非选项参数,所以他不是交互式shell。像su -[l] UserName -c "command",bash --login[-l] -c "command"这种带有-c选项的也不是交互式shell。
2、有-i选项的也是交互式shell
命令中有-i选项的就是交互式shell,比如 bash -i /path/to/script.sh,等等
3、我没按照字面意思也能大概判断。交互式shell就是能够在当前shell下输入,输出(一般带有-i选项的执行脚本,或带有-i -c 选项执行命令的也是交互式shell,他们是指在其他shell执行,然后退出shell,把结果返回到当前shell)
4、交互式shell,通过执行命令 echo $- 返回值一般有i
四、种模式配置文件文件加载过程
配置文件的作用: 持久保存用户的配置,只在登入时读取一次
运行中的Shell排列组合有这么几种:
登录交互式Shell
登录非交互式Shell
这两种模式,加载配置文件的顺序和过程相同
man bash 帮助文档中的描述如下:
When bash is invoked as an interactive login shell, or as a non-interactive shell with the --login option, it first reads and executes commands from the file /etc/profile, if that file exists. After reading that file, it looks for ~/.bash_profile, ~/.bash_login, and~/.profile, in that order, and reads and executes commands from the first one that exists and is readable. The --noprofile option may be used when the shell is started to inhibit this behavior.
When a login shell exits, bash reads and executes commands from the files~/.bash_logout and /etc/bash.bash_logout, if the files exists.
copy 鸟哥私房菜的一段,写得挺清楚
bash 在读完了整体环境设定的 /etc/profile 并借此调用其他配置文件后,接下来则是会读取使用户的个人配置文件。 在 login shell 的 bash 环境中,所读取得个人偏好配置文件其实主要有三个,依序分别是:
1. ~/.bash_profile
2. ~/.bash_login
3. ~/.profile
其实 bash 的 login shell 设定只会读取上面三个文件中的一个,读取的顺序是按照上面的顺序。
也就是说,如果~/.bash_profile存在,其他两个文件无论是否存在,都不会被读取如果~/.bash_profile不存在才会读取~/.bash_login,而前两者都不存在才会读取~/.profile
非登录交互式Shell
When an interactive shell that is not a login shell is started, bash reads and executes commands from ~/.bashrc, if that file exists.This may be inhibited by using the --norc option. The --rcfile file option will force bash to read and execute commands from file instead of ~/.bashrc.
上述的英文解释,是在centos系统上bash帮助手册上的一段,而在ubuntu系统上会有稍微不同,ubuntu系统
ubuntu系统上的描述
When an interactive shell that is not a login shell is started, bash reads and executes commands from /etc/bash.bashrc and~/.bashrc, if these files exist.
ubuntu系统上非登入交互式shell,启动时会主动读取/etc/bash.bashrc and~/.bashrc两个文件。
centos系统上非登入交互式shell,启动时只会主动读取~/.bashrc ,但是在~/.bashrc中有一段命令
# if [ -f /etc/bashrc ]; then #如果存在/etc/bashrc . /etc/bashrc #则会调用/etc/bashrc fi
我们可以看出centos系统中的/etc/bashrc 功能和ubuntu系统中的/etc/bash.bashrc一样。
非登录非交互式Shell
When bash is started non-interactively, to run a shell script, for example, it looks for the variable BASH_ENV in the environment, expands its value if it appears there, and uses the expanded value as the name of a file to read and execute. Bash behaves as if the following command were executed:
if [ -n "$BASH_ENV" ]; then . "$BASH_ENV"; fi
but the value of the PATH variable is not used to search for the file name.
非登入非交互式shell,那个文件也不会调用,但是,如果环境变量BASH_ENV存在,则会调用变量BASH_ENV所指代的文件。
但是,在测试时,非登录非交互式Shell加载 BASH_ENV变量测试过程中有点问题,问题链接 。有知道原因的请赐教。
手动读取配置文件
# source /etc/profile #或者下面这种方式 . /etc/profile
六、补充一下,以其他用户运行command命令时,是否加-或-l 选项 ,环境变量加载都不成功得原因
以下是好久之前网上的找的,没有原文章链接。
sudo command
sudo命令是以root的身份执行command命令,但是环境变量还是当前用户的,执行目录也仍然是当前目录
即环境变量和执行目录都不会切换到root
sudo command1 | command2 这种命令只会是command1有root权限,但是管道符后面的command则还是没有root权限。Sudo只会提升紧跟其后的那个命令的权限
su - username -c "command1;command2"
su命令是切换到另一个用户,环境变量会切换到username,执行目录会切换到目标用户username的家目录
提醒:
假设当前用户为普通用户lx(该用户没有ORACLE_SID这个环境变量),以lx用户执行命令
su - oracle -c "echo $ORACLE_SID"
输出会是空
su - username -c环境变量会切换到username,为什么没打印出oracle用户的ORACLE_SID环境变量呢?
因为双引号是不屏蔽$这个特殊字符的,在执行su - oracle -c "echo $ORACLE_SID"命令,
将先在当前用户下替换变量ORACLE_SID(当前用户的ORACLE_SID变量为空),然后发送给oracle执行的命令就成了 echo ""
我们的意图是将echo $ORACLE_SID这个命令发送给oracle用户,打印出oracle用户用户的环境变量ORACLE_SID,有以下解决方式:
1、su - oracle -c 'echo $ORACLE_SID' (单引号会屏蔽所有的特殊字符)
2、su - oracle -c "echo \$ORACLE_SID"
命令行命令“
su 与 su - 命令的却别:
su 命令仅切换用户身份,例如从A切换到B,执行whoami命令,显示的是用户B,但当前目录不会切换,
环境变量也仍未切换,仍为A用户的环境变量
su - 命令切换用户,A切换到B,会以登录B的流程执行,不仅会切换用户,还会执行.profile文件,
更换成B用户的环境变量,目录切换到B的家目录
参考:man bash 的帮助文档,鸟哥linux私房菜