Shell (1)基础.md

Shell简介

Shell 是一个应用程序,它连接了用户和 Linux 内核,让用户能够更加高效、安全、低成本地使用 Linux 内核,这就是 Shell 的本质。

Shell 本身并不是内核的一部分,它只是站在内核的基础上编写的一个应用程序,它和 QQ、迅雷、Firefox 等其它软件没有什么区别。然而 Shell 也有着它的特殊性,就是开机立马启动,并呈现在用户面前;用户通过 Shell 来使用 Linux,不启动 Shell 的话,用户就没办法使用 Linux。

Shell 本身支持的命令并不多,功能也有限,但是 Shell 可以调用其他的程序,每个程序就是一个命令,这使得 Shell 命令的数量可以无限扩展。

Shell 还可以让多个外部程序发生连接,在它们之间很方便地传递数据,也就是把一个程序的输出结果传递给另一个程序作为输入。

大家所说的 Shell 强大,并不是 Shell 本身功能丰富,而是它擅长使用和组织其他的程序。Shell 就是一个领导者,这正是 Shell 的魅力所在。

可以将 Shell 在整个 Linux 系统中的地位描述成下图所示的样子。注意“用户”和“其它应用程序”是通过虚线连接的,因为用户启动 Linux 后直接面对的是 Shell,通过 Shell 才能运行其它的应用程序。

Shell 支持编程。

Shell 是一种脚本语言,编写完源码后不用编译,直接运行源码即可。

Shell是运维人员必须掌握的技能。

常用的Shell有哪些

常见的 Shell 有 sh、bash、csh、tcsh、ash 等。

  1. sh
    sh 的全称是 Bourne shell,由 AT&T 公司的 Steve Bourne开发,为了纪念他,就用他的名字命名了。
    sh 是 UNIX 上的标准 shell,很多 UNIX 版本都配有 sh。sh 是第一个流行的 Shell。
  2. csh
    sh 之后另一个广为流传的 shell 是由柏克莱大学的 Bill Joy 设计的,这个 shell 的语法有点类似C语言,所以才得名为 C shell ,简称为 csh。
  3. tcsh
    tcsh 是 csh 的增强版,加入了命令补全功能,提供了更加强大的语法支持。
  4. ash
    一个简单的轻量级的 Shell,占用资源少,适合运行于低内存环境,但是与下面讲到的 bash shell 完全兼容。
  5. bash
    全称Bourne-Again Shell。
    bash shell 是 Linux 的默认 shell。
    bash 由 GNU 组织开发,保持了对 sh shell 的兼容性,是各种 Linux 发行版默认配置的 shell。

    bash 兼容 sh 意味着,针对 sh 编写的 Shell 代码可以不加修改地在 bash 中运行。

尽管如此,bash 和 sh 还是有一些不同之处:

  • 一方面,bash 扩展了一些命令和参数;
  • 另一方面,bash 并不完全和 sh 兼容,它们有些行为并不一致,但在大多数企业运维的情况下区别不大,特殊场景可以使用 bash 代替 sh。

查看 Shell

Shell 是一个程序,一般都是放在/bin或者/usr/bin目录下,当前 Linux 系统可用的 Shell 都记录在/etc/shells文件中。/etc/shells是一个纯文本文件,你可以在图形界面下打开它,也可以使用 cat 命令查看它。

通过 cat 命令来查看当前 Linux 系统的可用 Shell:

1
2
3
4
5
6
7
8
9
$ cat /etc/shells
/bin/sh
/bin/bash
/sbin/nologin
/usr/bin/sh
/usr/bin/bash
/usr/sbin/nologin
/bin/tcsh
/bin/csh

在现代的 Linux 上,sh 已经被 bash 代替,/bin/sh往往是指向/bin/bash的符号链接。

如果你希望查看当前 Linux 的默认 Shell,那么可以输出 SHELL 环境变量:

1
2
$ echo $SHELL
/bin/bash

输出结果表明默认的 Shell 是 bash。

Shell命令的基本格式

1
command [选项] [参数]

注意,Linux 的选项又分为短格式选项和长格式选项。

  • 短格式选项是长格式选项的简写,用一个减号-和一个字母表示,例如ls -l。
  • 长格式选项是完整的英文单词,用两个减号–和一个单词表示,例如ls –all。

一般情况下,短格式选项是长格式选项的缩写,也就是一个短格式选项会有对应的长格式选项。当然也有例外,比如 ls 命令的短格式选项-l就没有对应的长格式选项,所以具体的命令选项还需要通过帮助手册来查询。

Shell命令的本质

Shell 命令分为两种:

  • Shell 自带的命令称为内置命令,它在 Shell 内部可以通过函数来实现,当 Shell 启动后,这些命令所对应的代码(函数体代码)也被加载到内存中,所以使用内置命令是非常快速的。
  • 更多的命令是外部的应用程序,一个命令就对应一个应用程序。运行外部命令要开启一个新的进程,所以效率上比内置命令差很多。

Shell 内置命令的本质是一个自带的函数,执行内置命令就是调用这个自带的函数。因为函数代码在 Shell 启动时已经被加载到内存了,所以内置命令的执行速度很快。

Shell 外部命令的本质是一个应用程序,执行外部命令就是启动一个新的应用程序。因为要创建新的进程并加载应用程序的代码,所以外部命令的执行速度很慢。

不管是内置命令还是外部命令,它后面附带的数据最终都以参数的形式传递给了函数。命令后面附带的数据都是“原汁原味”地传递给了函数,对于程序而言,主要通过-来区分程序。

Shell脚本

在 test.sh 中输入代码:

1
2
#!/bin/bash
echo "Hello World !" #这是一条语句

第 1 行的#!是一个约定的标记,它告诉系统这个脚本需要什么解释器来执行,即使用哪一种 Shell;后面的/bin/bash就是指明了解释器的具体位置。

在新进程中运行Shell脚本有以下方法:

  1. 将 Shell 脚本作为程序运行:./test.sh
  2. 将 Shell 脚本作为参数传递给 Bash 解释器:/bin/bash test.sh

在当前进程中运行 Shell 脚本:
这里需要引入一个新的命令——source 命令。source 是 Shell 内置命令的一种,它会读取脚本文件中的代码,并依次执行所有语句。你也可以理解为,source 命令会强制执行脚本文件中的全部命令,而忽略脚本文件的权限。

source 命令的用法为:

1
source filename

也可以简写为:

1
. filename

两种写法的效果相同。对于第二种写法,注意点号.和文件名中间有一个空格。

Shell四种运行方式(启动方式)

我们可以直接使用 Shell,也可以输入用户名和密码后再使用 Shell;第一种叫做非登录式,第二种叫做登录式

我们可以在 Shell 中一个个地输入命令并及时查看它们的输出结果,整个过程都在跟 Shell 不停地互动,这叫做交互式。我们也可以运行一个 Shell 脚本文件,让所有命令批量化、一次性地执行,这叫做非交互式

总起来说,Shell 一共有四种运行方式:

  • 交互式的登录 Shell;
  • 交互式的非登录 Shell;
  • 非交互式的登录 Shell;
  • 非交互式的非登录 Shell。

非交互式必须在新进程中运行 Shell 脚本。

判断 Shell 是否是交互式

判断是否为交互式 Shell 有两种简单的方法。

  1. 查看变量-的值,如果值中包含了字母i,则表示交互式(interactive)。
  2. 查看变量PS1的值,如果非空,则为交互式,否则为非交互式,因为非交互式会清空该变量。

判断 Shell 是否为登录式

判断 Shell 是否为登录式也非常简单,只需执行shopt login_shell即可,值为on表示为登录式,off为非登录式。

shopt 命令用来查看或设置 Shell 中的行为选项,这些选项可以增强 Shell 的易用性。

同时判断交互式、登录式

要同时判断是否为交互式和登录式,可以简单使用如下的命令:

1
2
3
4
echo $PS1; shopt login_shell

或者
echo $-; shopt login_shell

Shell配置文件(配置脚本)的加载

无论是否是交互式,是否是登录式,Bash Shell 在启动时总要配置其运行环境,例如初始化环境变量、设置命令提示符、指定系统命令路径等。这个过程是通过加载一系列配置文件完成的,这些配置文件其实就是 Shell 脚本文件。

与 Bash Shell 有关的配置文件主要有 /etc/profile~/.bash_profile~/.bash_login~/.profile~/.bashrc/etc/bashrc/etc/profile.d/*.sh,不同的启动方式会加载不同的配置文件。

登录式的 Shell

Bash 官方文档说:如果是登录式的 Shell,首先会读取和执行 /etc/profiles,这是所有用户的全局配置文件,接着会到用户主目录中寻找 /.bash_profile、/.bash_login 或者 ~/.profile,它们都是用户个人的配置文件。

不同的 Linux 发行版附带的个人配置文件也不同,有的可能只有其中一个,有的可能三者都有,笔者使用的是 CentOS 7,该发行版只有 ~/.bash_profile,其它两个都没有。

如果三个文件同时存在的话,到底应该加载哪一个呢?它们的优先级顺序是 ~/.bash_profile > ~/.bash_login > ~/.profile。

如果 ~/.bash_profile 存在,那么一切以该文件为准,并且到此结束,不再加载其它的配置文件。

如果 ~/.bash_profile 不存在,那么尝试加载 /.bash_login。/.bash_login 存在的话就到此结束,不存在的话就加载 ~/.profile。

注意,/etc/profiles 文件还会嵌套加载 /etc/profile.d/*.sh,请看下面的代码:

1
2
3
4
5
6
7
8
9
for i in /etc/profile.d/*.sh ; do
if [ -r "$i" ]; then
if [ "${-#*i}" != "$-" ]; then
. "$i"
else
. "$i" >/dev/null
fi
fi
done

同样,~/.bash_profile 也使用类似的方式加载 ~/.bashrc:

1
2
3
if [ -f ~/.bashrc ]; then
. ~/.bashrc
fi

非登录的 Shell

如果以非登录的方式启动 Shell,那么就不会读取以上所说的配置文件,而是直接读取 ~/.bashrc。

~/.bashrc 文件还会嵌套加载 /etc/bashrc,请看下面的代码:

1
2
3
if [ -f /etc/bashrc ]; then
. /etc/bashrc
fi

编写自己的Shell配置文件

Shell 在登录和非登录时都会加载哪些配置文件了。对于普通用户来说,也许 ~/.bashrc 才是最重要的文件,因为不管是否登录都会加载该文件。

我们可以将自己的一些代码添加到 ~/.bashrc,这样每次启动 Shell 都可以个性化地配置。如果你有代码洁癖,也可以将自己编写的代码放到一个新文件中(假设叫 myconf.sh),只要在 ~/.bashrc 中使用类似. ./myconf.sh的形式将新文件引入进来就行了。

实例给 PATH 变量增加新的路径

当用户登录 Shell 时,PATH 变量会在 /etc/profile 文件中设置,然后在 ~/.bash_profile 也会增加几个目录。如果没有登录 Shell,PATH 变量会在 /etc/bashrc 文件中设置。

如果我们想增加自己的路径,可以将该路径放在 ~/.bashrc 文件中,例如:

1
PATH=$PATH:$HOME/addon

参考

  1. http://c.biancheng.net/shell/
  2. 腾讯课堂-享学课堂