2010年(130)
分类: LINUX
2010-01-15 21:56:05
GUI 非常优秀,但是要释放 Linux® 的真正威力,命令行是任何东西都无法取代的。在这篇文章中,Ian Shields 为您介绍了 bash shell 的一些主要特性,并重点介绍对 LPI 认证非常重要的特性。阅读完本文后,您将可以非常熟练地使用基本的 Linux 命令,比如 echo 和 exit、设置环境变量,以及收集系统信息。
|
概述
本文提供了对 bash shell 的某些主要特性的简介,并且涵盖了以下这些主题:
本文帮助您准备 Junior Level Administration (LPIC-1) 考试 101 中主题 103 下的目标 103.1。该目标的权值为 4。
shell 是一个非常丰富的环境,我们鼓励您进一步研究它。许多出色的书籍都专门介绍了 UNIX 和 Linux shell,而 bash shell 则是其中的重点;参见 参考资料 获得一些建议。
bash shell
bash shell 是 Linux 中的众多可用 shell 的其中之一。它也被称为 Bourne-again shell,这是以早期 shell(/bin/sh)的创建者 Stephen Bourne 命名的。Bash 在本质上是与 sh 兼容的,但是在函数和编程功能方面提供了许多改进。它合并了来自 Korn shell (ksh) 和 C shell (csh) 的特性,并且准备成为与 POSIX 兼容的 shell。
在我们深入研究 bash 之前,首先回忆一下,shell 是一个可以接受并执行命令的程序。它还支持编程结构,允许从比较小的部分构建复杂的命令。这些复杂的命令,即脚本,可以被保存为文件,从而构成新的命令。事实上,典型 Linux 系统中的许多命令都是脚本。
Shells 具有一些内置 命令,比如 cd、break 和 exec。其他命令是外部的。
Shell 还使用三个标准 I/O 流:
输入流为程序提供输入,通常来自终端键盘。输出流输出文本字符,通常输出到终端。终端最初是一个 ASCII 打字机或显示终端,但是现在往往为图形桌面上的一个窗口。有关重定向这些标准 I/O 流的更多细节将在本 系列 系列的另一篇文章中介绍。
在本文后面的内容中,我们将假设您知道如何获得一个 shell 提示。如果您不知道的话,请参考 developerWorks 文章 “Linux 开发新手基本任务”,其中介绍了如何完成这个操作以及其他内容。
如果使用不带图形桌面的 Linux 系统,或者在一个图形桌面中打开终端窗口,您将看到一个提示,可能类似于清单 1 所示。
[db2inst1@echidna db2inst1]$ ian@lyrebird:~> $ |
如果作为根用户(或者超级用户)登录,您看到的提示应该如清单 2 所示。
[root@echidna ~]# lyrebird:~ # # |
根用户具有相当大的权力,因此使用时应十分小心。当您拥有根权限时,大部分提示都包括一个 # 符号。普通用户的权限通常使用一个不同的字符加以区别,通常为一个美元符号($)。您实际看到的提示可能不同于本文显示的示例。您的提示也许包括用户名、主机名、当前目录、日期或输出提示的时间,等等。
这些文章包含的代码示例剪切自真实的 Linux 系统,使用了默认的提示。我们的根提示包含一个拖尾 # 号,因此您可以将它们与普通用户提示区分开,因为后者使用了一个拖尾 $ 符号。许多介绍此主题的书籍都一致使用这个约定。如果某些内容出错的话,那么检查示例中的提示。
命令和序列
现在您拥有了一个提示,让我们看看该如何处理它。shell 的主要功能是对您的命令进行解释,这样您就可以与 Linux 系统进行交互。在 Linux(以及 UNIX®)系统中,命令具有一个命令名称,以及选项 和参数。某些命令既没有选项,也没有参数,而另一些命令可能只具有其中之一。
如果一行代码中包含一个 # 字符,那么该行中的所有其他字符都可以被忽略。因此 # 字符可能表示一个注释以及一个根提示,这可以从上下文中看出来。
Echo
echo 命令将它的参数输出(或回传)到终端,如清单 3 所示。
[ian@echidna ~]$ echo Word Word [ian@echidna ~]$ echo A phrase A phrase [ian@echidna ~]$ echo Where are my spaces? Where are my spaces? [ian@echidna ~]$ echo "Here are my spaces." # plus comment Here are my spaces. |
在清单 3 的第三个示例中,所有额外的空间都被压缩到输出的单个空间中。为了避免这种情况,需要使用双引号(")或单引号(')将字符串括起。Bash 使用空格,比如空白、制表符和换行符,来将输入行分离到标记(token)中,后者随后被传递给命令。使用引号引用字符串将保留多余的空格并将完整的字符串作为一个单一标记。在上面的示例中,命令名称之后的每一个标记都是一个参数,因此我们具有的参数分别为 1、2、4 和 1。
echo 命令包含两个选项。echo 通常会在输出的末尾加一个拖尾换行符。使用 -n 选项可以禁用这个行为。使用 -e 选项可以使某些反斜杠转义字符具有特殊的含义。其中一些如表 1 所示。
转义 序列 |
作用 |
---|---|
\a | 警告 (bell) |
\b | 退格 |
\c | 禁用拖尾换行(与 -n 选项作用相同) |
\f | 换页(在视频显示中清空屏幕) |
\n | 换行 |
\r | 回车 |
\t | 水平制表符 |
转义和续行
在 bash 中使用反斜杠存在一个小问题。当未使用引号引用反斜杠字符(时),将作为一个转义来表示 bash 本身,用于保留以下字符的字面含义。这对于特殊的 shell 元字符是非常必要的,我们将在稍后讨论。这条规则有一个例外:反斜杠后跟一个换行符将致使 bash 合并这两个字符并将字符序列作为一个续行请求处理。这样做可以方便地将比较长的行断开,特别是在 shell 脚本中。
要使用 echo 命令或众多其他使用类似转义控制字符的命令来正确地处理上述字符序列,必须使用引号将转义序列括起,或作为引用字符串的一部分,除非您使用了另一个反斜杠,以使 shell 为命令保留一个反斜杠。清单 4 展示了反斜杠的各种使用示例。
[ian@echidna ~]$ echo -n No new line No new line[ian@echidna ~]$ echo -e "No new line\c" No new line[ian@echidna ~]$ echo "A line with a typed > return" A line with a typed return [ian@echidna ~]$ echo -e "A line with an escaped\nreturn" A line with an escaped return [ian@echidna ~]$ echo "A line with an escaped\nreturn but no -e option" A line with an escaped\nreturn but no -e option [ian@echidna ~]$ echo -e Doubly escaped\\n\\tmetacharacters Doubly escaped metacharacters [ian@echidna ~]$ echo Backslash \ > followed by newline \ > serves as line continuation. Backslash followed by newline serves as line continuation. |
注意,bash 在您输入包含不匹配引号的行时显示了一个特殊的 提示 (>)。您的输入字符串继续输入到下一行并包含一个换行符。
Bash shell 元字符和控制操作符(control operator)
Bash 具有多个元字符,这些元字符在未使用引号括起时,可以用来将输入分成多个单词。除了空格意外,这些元字符还包括:
我们将在本文的其他部分更详细地讨论其中一些元字符。现在要注意的是,如果您希望包含一个元字符作为文本的一部分,那么必须使用引号括起,或是使用反斜杠 (\) 进行转义,如清单 4 所示。
换行和某些元字符或元字符对也可以用作控制操作符。它们包括:
其中一些控制操作符允许您创建命令序列 或列表。
最简单的命令序列就是由两个命令组成的、用分号 (;) 分隔的序列。所有命令将按顺序执行。在任何可编程的环境中,命令返回成功或失败的指示;Linux 命令通常返回一个零值表示成功,并返回一个非零值表示失败。可以使用 && 和 || 控制操作符来将某些条件处理引入到列表中。如果使用控制操作符 && 来分隔两个命令,那么只有在第一个命令返回 0 表示退出时,才会执行第二个命令。如果使用 || 分隔命令,那么只有在第一个命令返回一个非零的退出代码时,才会执行第二个命令。清单 5 展示了一些使用 echo 命令的命令序列。这些例子并不怎么令人兴奋,因为 echo 返回了 0,但是当我们使用更多的命令时,您会看到更多例子。
[ian@echidna ~]$ echo line 1;echo line 2; echo line 3 line 1 line 2 line 3 [ian@echidna ~]$ echo line 1&&echo line 2&&echo line 3 line 1 line 2 line 3 [ian@echidna ~]$ echo line 1||echo line 2; echo line 3 line 1 line 3 |
退出
您可以使用 exit 命令终止一个 shell。或者可以提供一个 exit 代码作为参数。如果您在图形桌面上的终端窗口中运行 shell,那么窗口将关闭。类似地,如果使用 ssh 或 telnet(举例来说)连接到一个远程系统,那么您的连接将中断。在 bash shell 中,可以同时按下 Ctrl键和 d 键来退出。
让我们查看另一个控制操作符。如果您使用圆括号括起命令或命令列表,那么命令或序列将在一个 sub shell 中执行,因此 exit 命令将退出 sub shell,而不是退出您所在的 shell。清单 6 展示了结合了 && 和 || 以及两个不同的退出代码的示例。
[ian@echidna ~]$ (echo In subshell; exit 0) && echo OK || echo Bad exit In subshell OK [ian@echidna ~]$ (echo In subshell; exit 4) && echo OK || echo Bad exit In subshell Bad exit |
本文后面将介绍更多命令序列。
环境变量
当您在 bash shell 中运行时,有许多东西构成了您的环境,比如提示表单、主目录、工作目录、shell 名称、打开的文件、定义的函数,等等。您的环境包括许多由 bash 或您设置的变量。bash shell 还允许您拥有 shell 变量,可以将其导出 到您的环境,以供运行在 shell 中的其他进程或衍生自当前 shell 的其他 shell 使用。
环境变量和 shell 变量都具有一个名称。可以通过在名称前面加一个 “$” 前缀来引用变量的值。表 2 显示了您将经常遇到的一些 bash 环境变量。
名称 | 作用 |
---|---|
USER | 已登录用户的名称 |
UID | 用数字表示的已登录用户的用户 id |
HOME | 用户的主目录 |
PWD | 当前的工作目录 |
SHELL | shell 的名称 |
$ | 进程 id(或运行的 bash shell 或其他进程的 PID |
PPID | 启动当前进程的进程的 id(即父进程的 id) |
? | 上一个命令的退出代码 |
清单 7 展示了这些常见 bash 变量的内容。
[ian@echidna ~]$ echo $USER $UID ian 500 [ian@echidna ~]$ echo $SHELL $HOME $PWD /bin/bash /home/ian /home/ian [ian@echidna ~]$ (exit 0);echo $?;(exit 4);echo $? 0 4 [ian@echidna ~]$ echo $ $PPID 2559 2558 |
|
通过输入一个名称并在其后紧接着输入一个等号 (=),您将创建或设置 一个 shell 变量。如果变量存在的话,可以修改它来分配新值。变量需要区分大小写,因此 var1 和 VAR1 表示两个不同的变量。一般来讲,变量(特别是导出的变量)都是大写的,但是这并不是强制要求。理论上来说,$$ 和 $? 属于 shell 参数 而不是变量。它们只能被引用;您不能为它们分配值。
在创建 shell 变量时,您通常需要将其导出 到环境中,这样才可以用于从这个 shell 中启动的其他进程。导出的变量不能 用于父 shell。您使用 export 命令导出变量名。作为 bash 中的一种简单方法,您可以在一个步骤中同时分配值并导出变量。
为了演示分配和导出,让我们在 bash shell 中运行 bash 命令,然后从新的 bash shell 中运行 Korn shell (ksh)。我们将使用 ps 命令显示有关当前运行命令的信息。我们将在本系列的另一篇文章中了解有关 ps 的更多信息(参见 参考资料 获得系列路线图)。
[ian@echidna ~]$ ps -p $ -o "pid ppid cmd" PID PPID CMD 2559 2558 -bash [ian@echidna ~]$ bash [ian@echidna ~]$ ps -p $ -o "pid ppid cmd" PID PPID CMD 2811 2559 bash [ian@echidna ~]$ VAR1=var1 [ian@echidna ~]$ VAR2=var2 [ian@echidna ~]$ export VAR2 [ian@echidna ~]$ export VAR3=var3 [ian@echidna ~]$ echo $VAR1 $VAR2 $VAR3 var1 var2 var3 [ian@echidna ~]$ echo $VAR1 $VAR2 $VAR3 $SHELL var1 var2 var3 /bin/bash [ian@echidna ~]$ ksh $ ps -p $ -o "pid ppid cmd" PID PPID CMD 2840 2811 ksh $ export VAR4=var4 $ echo $VAR1 $VAR2 $VAR3 $VAR4 $SHELL var2 var3 var4 /bin/bash $ exit [ian@echidna ~]$ echo $VAR1 $VAR2 $VAR3 $VAR4 $SHELL var1 var2 var3 /bin/bash [ian@echidna ~]$ ps -p $ -o "pid ppid cmd" PID PPID CMD 2811 2559 bash [ian@echidna ~]$ exit exit [ian@echidna ~]$ ps -p $ -o "pid ppid cmd" PID PPID CMD 2559 2558 -bash [ian@echidna ~]$ echo $VAR1 $VAR2 $VAR3 $VAR4 $SHELL /bin/bash
目前为止,我们的所有变量引用都使用空格作为结束,因此可以很清楚地显示变量名的终止位置。实际上,变量名可以只包含字母、数字和下划线字符。shell 知道变量名将在出现另一个字符的位置上终止。有时您需要在含义模糊的表达式中使用变量。在这种情况下,可以使用花括号来突出显示命令名,如清单 10 所示。 清单 10. 使用花括号表示变量名
Env env 在不包含任何选项或参数的情况下将显示当前的环境变量。可以使用它来在定制环境中执行命令。-i(或 -)选项将在运行命令之前清空当前环境,而 -u 选项取消了您不喜欢传递的环境变量。 清单 11 展示了不带任何参数的 env 命令的部分输出,以及在无父环境的情况下调用不同 shell 的三个例子。在我们进行讨论之前请仔细查看它们。 注意:如果系统还没有安装 ksh (Korn) 或 tcsh shell,那么您需要自己动手安装这些 shell。 清单 11. env 命令
注意,bash 设置了 SHELL 变量,但是没有将其导出到环境中,尽管 bash 在环境中创建了另外三个变量。在 ksh 例子中,我们拥有两个变量,但是我们回传 SHELL 变量的值的行为生成了一个空白行。最后,tcsh 并没有创建任何环境变量,并在我们尝试引用 SHELL 的值的时候生成了一个错误。 Unset 和 set 清单 11 展示了 shell 处理变量和环境的各种行为。虽然本文主要关注 bash,但是您最好知道并非所有 shell 都具有相同的行为。此外,shell 将根据它们是否是登录 shell 来做出不同的行为。目前,我们将登录 shell 定义为您在登录到一个系统时获得的 shell;如果愿意的话,您可以启动其他 shell 来作为登录 shell。上面使用 env -i 启动的三个 shell 并不是登录 shell。尝试向 shell 命令本身传递 -l 选项,看看使用登录 shell 会出现什么结果。 现在让我们来尝试在这些非登录 shell 中显示 SHELL 变量的值:
您可以使用 unset 命令来取消一个变量并从 shell 变量列表中移除它。如果变量被导出到环境中,那么将从环境中删除这个变量。可以使用 set 命令来对 bash(或其他 shell)的行为进行许多控制。Set 是一个内置在 shell 中的功能,因此各种选项都是特定于 shell 的。在 bash 中,-u 选项将使 bash 报告一个有关未定义变量的错误,而不是将它们作为已定义的空变量。可以使用 - 对 set 启用各种选项,并使用 + 来关闭选项。可以使用 echo $- 显示当前设置的选项。 清单 12. Unset 和 set
如果使用不包含任何选项的 set 命令,它将显示所有 shell 变量及变量值(如果有的话)。还有另一个命令 declare,可以用它创建、导出和现实 shell 变量的值。可以通过手册页研究其他各种 set 选项和 declare 命令。我们稍后将讨论 手册页。 Exec 最后将要介绍的命令是 exec。可以使用 exec 命令来运行将替换当前 shell 的另一个程序。启动 13 启动了一个子 bash shell 并使用 exec 来将它替换为一个 Korn shell。从 Korn shell 退出后,您将回到初始的 bash shell(本例为 PID 2852)中。 清单 13. 使用 exec
使用 uname 显示系统信息 uname 命令输出有关您的系统及其内核的信息。清单 14 展示了 uname 的各种选项以及生成的信息;每个选项在表 3 中进行了定义。 清单 14. uname 命令
|