shell是命令行解释和执行器。它是介于使用者和 UNIX/Linux操作系统核心程序(kernel)之间的一个接口。当你登录(login)时,一个交互式的shell会跟着启动,并提示你输入命令。在你键入一条命令后,剩下的就是shell 的本职工作了——解释命令行、获得规范的命令结构,处理通配符、重新定向、管道和作业控制,然后搜索函数、内外部命令,最后执行命令。采用作业控制机制的目的是提供用户介入的机会,允许用户使用内部命令或键盘信号来启停作业。 2.8.1 勤勤恳恳的bash UNIX/Linux下的shell俱乐部里的成员不少,除了Bourne shell(/bin/sh)以外,还有C shell(/bin/csh)、Korn shell(/bin/ksh)、Bourne again shell(/bin/bash)、Tenex C shell(tcsh)等等。Bourne shell 是标准的 UNIX shell,以前常被用来做为管理系统之用,提示符号的默认值是 $。大部份的系统管理命令文件,例如rc start、stop 与shutdown 都是Bourne shell 的命令。 Bash(Bourne Again shell)是Linux下经典的shell。它对Bourne shell做了向下兼容,保持了Bourne shell原有的简洁和快速的风格,融入了许多C shell 与Korn shell 的功能。bash工程的总代码量大约13万行左右,不仅出色地完成了命令行解析的任务,支持用管道和重定向等手段协同执行命令,而且还提供了强大的脚本编程能力,并具备作业管理功能。在一般的Linux发行版中,bash是/bin下几个重量级的“人物”之一。 在第1章中我们对bash的一些特点有所提及,例如: 别名功能(alias):为一个命令建立另一个名称。它的功效就好像一个宏,展开成为它所代表的命令,主要目的是为了简化命令输入。 历史命令(history):用 history 工具程序记录了最近你执行过的命令。命令是由 1 开始编号,默认值为500。你可以在终端上键入 history,屏幕上将会显示你最近执行过的命令清单,每个命令前还带有编号。更方便的是使用上下键,一次放一个历史“事件”。 工作控制(job contorl):Linux是一个多用户的操作系统,它还支持多任务同时运行。对于单核处理器虽然一个时间只有一个进程在运行,但是Linux按时间片调度多个进程,使它们看起来好像同时运行似的。下面几个命令控制进程运行。 ps --列出正在运行的进程 kill --向一个或多个进程发信号(经常是杀掉进程) jobs --列出自己运行的进程 bg --将进程放到后台 fg --将进程放到前台 举一个例子,这个例子虽然有些古老,但是对讲述进程控制还是蛮实用的。假如你从命令行运行xload,系统开始加载界面。你可能注意到了在程序启动以后你的提示符并没有消失。这是因为shell在等待程序完成后把控制权交给你。当你关掉xload窗口,xload结束又返回到提示符。如何把程序放到后台运行呢?在程序名xload后面加上 “&”就行。如果你没有在xload后面加入“&”符号,输入control-z,程序会“悬挂”在那里。虽然进程是存在的,但是处于闲置状态。屏幕的返回值如下: ^Z [1]+ Stopped xload 输入bg后就可以把xload推到后台运行,使用jobs可以显示进程列表。但是我更喜欢用ps,它提供的服务更全面、更给力。 如果需要杀掉xload这个进程,就要用kill命令。有些进程相当顽固,你直接用killall程序名这个命令还真杀不死它。那你只能用ps命令先找到它的pid,再用kill -9相应的pid彻底把它干掉。要是想用一行命令把它处理掉,敲入ps -aef | awk '/xload/{print "kill -9",$2}',这样咱就把xload进程给杀死了。 kill是用来杀掉进程,但它的实际目的远不止如此,它会向进程发信号,进程听到从操作系统来的信号后开始回应,很“优雅”地退出操作。例如当用户退出系统或者计算机关机时,进程收到这些信号后,在离职之前做好保存工作。kill提供了一系列的信号,kill -l后显示提供的信号列表: (1)SIGHUP (2)SIGINT (3)SIGQUIT (4)SIGILL (5)SIGTRAP (6)SIGABRT (7)SIGEMT (8)SIGFPE (9)SIGKILL (10)SIGBUS (11)SIGSEGV (12)SIGSYS (13)SIGPIPE (14)SIGALRM (15)SIGTERM (16)SIGURG (17)SIGSTOP (18)SIGTSTP (19)SIGCONT (20)SIGCHLD (21)SIGTTIN (22)SIGTTOU (23)SIGIO (24)SIGXCPU (25)SIGXFSZ (26)SIGVTALRM (27)SIGPROF (28)SIGWINCH (29)SIGINFO (30)SIGUSR1 (31)SIGUSR2 信号还真不少! 管道(pipe)与重定向(redirect):“|”这个符号你认识吗?它是管道操作符,是指前一个命令的输出作为后一个命令的输入。I/O重定向通常与文件描述符有关,用 < 来改变读入的数据信道(stdin),使它从指定的文件读入;用 > 来改变送出的数据信道(stdout,stderr),使它输出到指定的文件。我会在“第5章 shell脚本编程”中做详细讲解。 2.8.2 环境变量 当登录系统后,你才有资格通过shell与Linux沟通。这时候shell启动,并从启动它的/bin/login程序中继承了多个变量、I/O流和进程特征。如果遇到需要后台处理、执行整组命令以及脚本的情况,父shell也会派生子shell应付这些工作,子shell从父亲那里继承环境。这里的环境包括进程的权限、工作目录、文件创建掩码、特殊变量、打开的文件和信号。变量包括局部变量和环境变量。局部变量是私有的,无法传递给子shell。与之相反,环境变量可由父shell传递给子shell,子shell传递给孙shell……子子孙孙,无穷尽也。 所谓的读入系统的环境变量包括PATH、HOME、LOGNAME、IFS和SHELL 等等,为了区别与自定义变量的不同,环境变量通常以大写字符来表示。可以通过set、env和export设置环境变量,使用unset命令来清除设置,使用readonly来设置只读属性。 请看例子: export ENVTEST= "ENV1" env | grep ENVTEST 结果: ENVTEST= ENV1 unset $ENVTEST env | grep $ENVTEST 结果? 2.8.3 bash的配置文件 前面讲了在输入登录用户名和密码后shell才启动,这是login shell。还有一种non-login shell,不需要做重复的登录操作获取bash界面。例如在x-window环境下来启动终端,测试终端界面不需要再次输入账户与密码,这个bash环境就是non-login shell。login和non-login有什么区别呢?那得先从bash的配置文件说起。 1. 系统设置文件 只有login shell才会读取系统设置文件/etc/profile。它是系统整体的配置文件,该配置文件里包含很多重要的变量信息,每个用户登录取得bash后一定会读取这个配置文件。如果你想要所设置的环境变量对所有用户起作用,就要在这个地方设置。该文件主要有以下设置变量: #PATH:会根据UID决定PATH变量要不要含有sbin的系统指令目录; pathmunge () { if !echo $PATH | /bin/egrep -q "(^|:)$1($|:)" ; then if [ "$2" = "after" ] ; then PATH=$PATH:$1 else PATH=$1:$PATH fi fi } …… #USER:根据用户的账号设置此变量内容; USER="`id -un`" LOGNAME=$USER #MAIL:根据账户设置/var/spool/mail/账号名称; MAIL="/var/spool/mail/$USER" #依据主机的hostname指令设置此变量的内容; HOSTNAME=`/bin/hostname` HISTSIZE=2000 #HISTSIZE:历史命令记录数。 HISTTIMEFORMAT='[%F %T] ' 除了完成以上设置,/etc/profile还会调用如下的外部设置文件: /etc/inputrc:用来设置bash的热键、[Tab]是否有声音等信息。 /etc/profile.d/*.sh:这个目录下的文件规定了bash的操作界面、语系以及一些公共的命令别名。 /etc/sysconfig/i18n:这个文件是供/etc/profile.d/lang.sh调用,决定bash默认使用何种语系。 2. 用户的个性设置文件 login shell读完了/etc/profile配置文件后,接下来就会读取用户的个人配置文件。个人配置文件主要有三个隐藏文件,依次是:~/.bash_profile 、/.bash_login 和 ~/.profile。如果~/.bash_profile存在,那么bash就不会理睬其他两个文件。如果~/.bash_profile不存在,bash才会读取~/.bash_login。而前两个文件都不存在的话,bash才会读取~/.profile文件。个人设置文件主要是获取与用户有关的环境、别名和函数等。如果~/.bashrc存在的话,~/.bash_profile还会调用它,所以你可以把你的一些环境设置写到~/.bashrc这个文件中。在用户目录下,还有两个个人文件~/.bash_history和~/.bash_logout。默认情况下,历史命令就记录在bash_history中。每次登录bash后,bash读取这个文件,将所有的历史命令读入内存。 ~/.bash_logout告诉系统在离开“我”之前需要帮“我”做什么。默认情况下,文件只让bash清掉屏幕的消息。你可以添加一些信息到在这个文件中,例如备份要求等。 3. 用户的通用设置 系统层的函数、别名和环境等设置一般在/etc/profile。但是对于非交互的non-login shell,我们也希望通过~./bashrc做一些的设置。如果/etc/bashrc存在的话,它会被~./bashrc调用。它的主要工作有: (1)依据不同的UID给出umask值 (2)依据不同的UID给出PS1变量 (3)调用/etc/profile.d/*.sh的设置 图2.7和图2.8分别展示了login shell和non login shell的整个配置文件处理流程: 图2.7 login shell配置文件处理流程 图2.8 non login shell配置文件处理流程 个人需要的设置写在“~./bashrc”文件中即可。由于/etc/profile与~/.bash_profile都是在取得login shell的时候才会读取配置文件,所以修改这两个文件中的设置后,需要再登录相应的配置才能生效。其他的配置可以通过source命令将配置文件的内容读入当前shell环境中。