shell 编程(一):简介


shell 简介

shell 是 unix 系统上用来控制系统运行的程序,有以下的特点:

  • Shell 是一个用 C 语言编写的程序,它是用户使用 Linux 的桥梁。
  • Shell 既是一种命令语言,又是一种程序设计语言。
  • Shell 是指一种应用程序,这个应用程序提供了一个界面,用户通过这个界面访问操作系统内核的服务。

shell 的作用是解释执行用户的命令,执行方式有以下两种:

  • 交互式(Interactive):用户输入一条命令,Shell就解释执行一条。
  • 批处理(Batch):用户事先写一个 Shell 脚本(Script),其中有很多条命令,让Shell 一次把这些命令执行完,而不必一条一条地敲命令。

shell 脚本和编程语言很相似,也有变量和流程控制语句,但 shell 脚本是解释执行的,不需要编译,shell 程序从脚本中一行一行读取并执行这些命令,相当于一个用户把脚本中的命令一行一行敲到 shell 提示符下执行。

shell 版本

由于历史原因,UNIX 系统上有很多种 Shell:

  • sh(Bourne Shell):由 Steve Bourne 开发,各种 UNIX 系统都配有sh。

  • csh(C Shell):由 Bill Joy 开发,随 BSD UNIX 发布,它的流程控制语句很像 C 语言,支持很多 Bourne Shell 所不支持的功能:作业控制,命令历史,命令行编辑。

  • ksh(Korn Shell):由 David Korn 开发,向后兼容 sh 的功能,并且添加了 csh 引入的新功能,是目前很多 UNIX 系统标准配置的 shell,在这些系统上 /bin/sh 往往是指向 /bin/ksh 的符号链接。

  • tcsh(TENEX C Shell):是 csh 的增强版本,引入了命令补全等功能,在 FreeBSD、Mac OS X 等系统上替代了 csh。

  • bash(Bourne Again Shell):由 GNU 开发的 shell,主要目标是与 POSIX 标准保持一致,同时兼顾对 sh 的兼容, bash 从 csh 和 ksh 借鉴了很多功能,是各种 Linux 发行版标准配置的 Shell,在 Linux 系统上 /bin/sh 往往是指向 /bin/bash 的符号链接。虽然如此,bash 和 sh 还是有很多不同的,一方面,bash 扩展了一些命令和参数,另一方面, bash 并不完全和 sh 兼容,有些行为并不一致,所以 bash 需要模拟 sh 的行为:当我们通过 sh 这个程序名启动 bash 时, bash 可以假装自己是 sh,不认扩展的命令,并且行为与 sh 保持一致。

  • Zsh(Z shell):Zsh 对 Bourne shell 做出了大量改进,同时加入了 Bash、ksh 及 tcsh 的某些功能。命令补全功能非常强大,可以补齐路径,补齐命令,补齐参数等。

可以通过如下的命令来查看当前系统中所有用户所对应的 shell 版本:

$ vi /etc/passwd

执行 shell

编写一个简单的 hello world:

#! /bin/sh
echo "hello world"

shell 脚本中用 # 表示注释,相当于 C 语言的 // 注释。

但如果 # 位于第一行开头,并且是 #!(称为Shebang)则例外,它表示该脚本使用后面指定的解释器 /bin/sh 解释执行。

接下来执行该脚本,有如下的几种执行方式:

方式一:直接执行

可以给该脚本文件加上可执行权限然后执行:

$ chmod a+x test.sh
$ ./test.sh

方式二:指定解释器执行

$ /bin/sh ./test.sh

以这种方式执行不需要test.sh文件具有可执行权限。

方式三:使用 source 执行

$ source test.sh

方式四:使用 . 执行

$ . test.sh

使用 source 或者 . 命令来执行脚本文件是直接在交互式的 shell 下逐行执行脚本中的命令。至于为什么,那么便得介绍下 shell 命令执行的过程了。

shell 命令执行过程

  • 当用户在命令行输入命令后,一般情况下 shell 会 fork 出一个子进程,并且 exec 执行 shell 中的命令。

  • 但是 shell 中的内建命令例外,执行内建命令相当于调用 shell 进程中的一个函数,并不创建新的进程。

内建命令虽然不创建新的进程,但也会有 Exit Status(虽然内建命令不创建新的进程,但执行结束后也会有一个状态码,也可以用特殊变量 $? 读出。) :

  • 通常用 0 表示成功
  • 非零表示失败

而 source 或者 . 命令是 shell 的内建命令,这种方式是不会创建子 shell 进程的,而是直接在交互式 shell下 逐行执行脚本中的命令。

注:查看 shell 中的内建命令的方式如下:

$ man bash-builtins