Chinaunix首页 | 论坛 | 博客
  • 博客访问: 893570
  • 博文数量: 282
  • 博客积分: 10843
  • 博客等级: 上将
  • 技术积分: 2435
  • 用 户 组: 普通用户
  • 注册时间: 2006-07-01 15:23
文章分类

全部博文(282)

文章存档

2013年(1)

2012年(18)

2011年(14)

2010年(30)

2009年(48)

2008年(55)

2007年(55)

2006年(61)

分类:

2006-09-03 12:07:21

   
在 Bash shell 中工作

关于 Bash 的概述
 
    大多数计算机用户并不了解他们的计算机中执行所有实际工作的那些技术。例如,在网上冲浪、发送和接收电子邮件或编写文档时,您与计算机进行着很高层次的交互。称为操作系统 的软件将用户从底层细节中隔离出来。操作系统中有一个称为内核 的特殊组件,它直接与硬件进行交互。

    许多年来,像 Microsoft Windows、K Desktop Environment (KDE)、GNU Network Object Model Environment (GNOME)、Apple's Aqua 和 X Consortium's X11 等图形界面都建立在基础操作系统之上,以简化用户通过计算机执行的日常任务。然而,以前并不是这样的。在窗口系统流行之前,计算机用户通过命令行提示符进行操作,直接与内核进行交互以完成他们的工作。因为这种方式使用困难并且容易出错,所以开发了称为 shell 的新软件层,它可以简化与内核进行通信的任务。

UNIX shell 的简史

    第一个广泛使用的 shell 由 AT&T Bell Labs 的 Stephen R. Bourne 于 1974 年开发完成,它称为 Bourne shell。这个 shell 使得用户可以更加轻松地与 Bell Labs 的 UNIX 研究版本的第七版进行交互。Bourne shell 提供了完整的编程语言,该语言允许用户控制程序输入和输出,并且包含了功能强大的表达式匹配功能。

    差不多在同一时间,University of California, Berkeley 开发了另外一种 UNIX 实现,称为 BSD UNIX(表示 Berkeley Software Distribution)。在 1978 年,Berkeley 的 Bill Joy 开发了一种称为 C Shell (/bin/csh) 的新的 UNIX shell,其中添加了一些新的功能,包括作业控制、别名和经过改进的交互功能。而且,对 C Shell 的编程特性进行了改进,使其更接近于 C 编程语言。然而,其中的一些改进却使得 shell 脚本的开发和维护变得更复杂。

    随后又开发出了其他的 shell,包括 Korn shell (/bin/ksh) 和 TC shell (/bin/tcsh),它们分别对 Bourne shell 和 C Shell 这两种原始的 shell 进行了扩展。虽然这两种 shell 提供了一些改进,但是它们都存在着各自的缺陷。Korn shell 是封闭原始代码的,而 TC shell 与原始的 C Shell 一样存在许多脚本编写方面的困难。不久以后,提出了一项国际规范,称为 POSIX(可移植操作系统接口)1003.2,该规范说明了 shell 应该如何与用户进行交互。

    Bash (/bin/bash) 是 Bourne-Again SHell 的首字母缩写,最初由自由软件基金会的 Brian Fox 编写,并且克服了以前的各种 shell 的局限性。Bash 构建于 Bourne shell 的传统之上,它具有下列优点:

    * 它提供了功能强大且易于使用的脚本编写语言。
    * 它集成了 C Shell 系列 shell 的交互式使用的优点。
    * 它是免费的,并且完全开放源码。
    * 它提供了兼容于 POSIX 1003.2 规范的实现。

Bash 的特性

    Bash 具有悠久的历史,它提供了一些有价值的特性以改进 shell 的交互式使用,并且简化了 shell 脚本的开发,而这些脚本是调用 shell 特性以实现任务自动化的简单程序。对 Bash 进行自定义非常容易,可以通过特殊的启动初始化文件和特定的 Bash 选项来实现。表 1 列举了 Bash 的一些基本特性,它们改进了 Bash 的交互式使用。

表 1. Bash shell 的基本特性
特性             说明
命令行编辑     这个特性使得您可以轻松地在命令行中移动光标或编辑文本。
历史命令     这个特性允许您重放 或有选择地编辑和恢复一项已在命令行中输入过的命令。
IO 重定向     这个特性使得您可以很容易地更改程序从何处获得输入或将输出发送到何处。
别名             这个特性允许您为单行的命令创建缩略替代。
函数             这个特性允许您为多行的命令创建缩略替代。

    Bash 提供了许多有价值的特性以简化 shell 的开发和维护,但这些内容超出了本教程的范围。

在 Bash 的命令提示符处进行工作

    Bash 是运行于 UNIX 终端中的一个程序。因此,必须启动一个新的终端应用程序来使用它。在缺省情况下,您的系统可能配置为使用不同的 shell。要查看您所运行的 shell 的种类,请在终端窗口的命令提示符处输入 echo $SHELL,然后按下 Enter(或 Return)。如果应答为 /bin/bash,那么就表明您正在运行 Bash。如果您得到了不同的应答,那么您可能正在运行不同的 shell。

    要查看您的系统中是否安装了 Bash,在命令行中输入 whereis bash。这个命令可以定位 Bash 并且提供该程序的完整路径。如果您的系统中没有安装 Bash,那么您可以免费下载并安装最新的版本(请参见参考资料部分)。如果您的系统中已经安装了 Bash,那么您可以使用 chsh bash 命令将缺省 shell 更改为 Bash。请注意,在有的系统中,如 MAC OS X,这个命令稍微有些不同。您可以在命令提示符处输入 bash,然后按下 Enter(或 Return),这样就可以启动一个新的 Bash shell(只要您的系统中已经安装了 Bash,即使缺省情况下运行的是另一种 shell)。

在命令行中进行工作

    在 Bash 运行的过程中,您可以通过更改不同的选项,很容易地对其进行自定义。要查看这些选项的列表,请在 Bash 提示符处输入 set -o 命令,如清单 1 所示。请注意,在这个代码清单中,Bash 提示符是字符串 rb$。该提示符可能与您系统中的提示符有所不同。在本教程后面的内容中,我将介绍如何自定义提示符。

清单 1. 在 Bash 中设置选项

                    
rb$ echo $SHELL
/bin/bash
rb$ whereis bash
/bin/bash
rb$ set -o
allexport               off
braceexpand             on
emacs                   on
errexit                 off
hashall                 on
histexpand              on
history                 on
ignoreeof               off
interactive-comments    on
keyword                 off
monitor                 on
noclobber               off
noexec                  off
noglob                  off
nolog                   off
notify                  off
nounset                 off
onecmd                  off
physical                off
posix                   off
privileged              off
verbose                 off
vi                      off
xtrace                  off

    如本例所示,Bash 中有大量的选项,您可以对它们进行更改以控制 Bash 如何与用户进行交互。其中一些可以启用的比较有价值的选项包括 emacs 和 history 选项。前者允许您使用 Emacs 键绑定在命令行中进行移动,而后者则表示 shell 是否应该维护一个执行过的命令的列表,以便您可以轻松地重放它们。

    如果您从来没有使用过流行的 Emacs(或 XEmacs)编辑器,那么可能对 Emacs 键绑定并不很熟悉。然而,它们很容易学习,并且提供了一种功能强大的方法以便在长命令中进行移动。其中一些比较常用的键绑定包括:

    * CTRL+A 移动到当前行的起始处。
    * CTRL+E 移动到当前行的末尾。
    * CTRL+K 删除当前行中光标所在位置后的所有字符。

    掌握这些(及其相关的)键绑定可以使得在命令提示符处所进行的工作变得更加容易。同样地,启用 history 选项将使得您可以更轻松地对以前的命令进行重放、或编辑之后再重放。对于大多数的 Bash 安装,其历史记录的缺省值为最近 500 条命令,在大多数情况下,这应该已经足够了。但是如果还不够,您可以很容易地更改这个值,在本教程后面的内容中将对这个问题进行介绍。要在历史记录文件中进行前后移动,您可以使用下列键绑定:

    * CTRL+P(表示上一条),或向上箭头键,移动到历史缓冲区中的上一条命令。
    * CTRL+N(表示下一条),或向下箭头键,移动到历史缓冲区中的下一条命令。
    * CTRL+R(表示反向搜索)对以前的命令进行搜索。

    您还可以使用 history 命令来显示以前的命令,每条命令都带有它在历史记录缓冲区中的编号。然后,您可以使用该编号,以感叹号 (!) 作为开始,执行缓冲区中一条特定的命令,比如 !382。通过使用感叹号加上一个负数,您还可以对历史记录缓冲区进行相对索引。例如,!-2 执行历史记录缓冲区中的倒数第二条命令。因为历史记录缓冲区可以跨越登录会话,所以它为前面的命令的重放提供了一种功能强大的技术。

    您可能注意到清单 1 中还介绍了其他的一些选项,根据您的 Bash shell 的确切版本的不同,其中的一些选项也稍有不同(或者具有不同的缺省值)。通过输入 set -o option-name ,您可以很容易地设置这些选项;而通过输入 set +o option-name ,您可以很容易地撤销这些选项。例如,set -o emacs 打开了 Emacs 键绑定选项。

阅读手册

    要了解关于 Bash 选项或 UNIX 系统中任何命令的更详细的信息,您可以使用联机 UNIX 手册。使用 man 命令来访问它。清单 2 显示了 Bash 的手册页面。

清单 2. 阅读 Bash 的 UNIX man 页面
                    
rb$ man bash
BASH(1)                                                               BASH(1)
NAME
       bash - GNU Bourne-Again SHell
SYNOPSIS
       bash [options] [file]
COPYRIGHT
       Bash  is Copyright (C) 1989-2004 by the Free Software Foundation, Inc.
DESCRIPTION
       Bash is an sh-compatible command language  interpreter  that  executes
       commands  read  from  the  standard  input  or from a file.  Bash also
       incorporates useful features from the Korn and C shells (ksh and csh).
       Bash  is  intended to be a conformant implementation of the IEEE POSIX
       Shell and Tools specification (IEEE Working Group 1003.2).
OPTIONS
       In addition to the single-character shell options  documented  in  the
       description  of the set builtin command, bash interprets the following
       options when it is invoked:
:

在 Bash 中使用文件和目录

    大多数可能在 Bash 中进行的工作都将以某种方式与 UNIX 文件系统协同完成。如果您曾经使用过图形文件浏览器,那么您可能知道文件系统的树型模拟。对于命令行来说,这也是一样的。所有的文件和目录都以 / 为根,它是文件系统的根节点。表 2 列举了大多数 UNIX 系统共有的几个标准目录。

表 2. 常用的 UNIX 系统目录
目录     描述
/     这个目录是 UNIX 系统的根目录,它包含了所有其他的文件。
/bin     这个目录包含了系统应用程序文件的二进制版本,比如 Bash 程序本身。
/dev     这个目录包含了表示诸如磁盘驱动器这样的物理设备的伪文件。
/etc     这个目录包含了大部分的系统配置文件。
/lib     这个目录包含了系统应用程序所需的库文件。
/opt     这个目录包含了可选的系统组件或应用程序。
/tmp     这个目录包含了系统或用户应用程序使用的临时文件。
/usr     这个目录包含了用户和非关键的系统应用程序及相关组件。
/var     这个目录包含了系统应用程序所需的各种文件,如日志或 spool 文件。

在 Bash 中使用目录

    有一些 UNIX 命令使得您可以很容易地创建、列举或删除目录,并且可以更改您当前工作的目录:

    * cd 用来将当前工作目录更改为您的 home 目录。
    * cd dirname 将当前工作目录更改为 dirname 目录。
    * ls dirname 列举 dirname 目录中的内容。
    * mkdir dirname 创建一个名为 dirname 的目录。
    * pwd 显示当前工作目录的完整路径。
    * rmdir dirname 删除名为 dirname 的目录。

    要使用这些程序中的任何一个,只需要在 Bash 提示符处输入相应的命令(包括所需要的任何目录的名称),然后按下 Enter(或 Return)。

    对于目录的名称,还有几个有用的快捷表示方式:

    * 单点号 (.) 表示当前工作目录。
    * 双点号 (..) 表示当前工作目录的父目录。
    * 波浪符号 (~) 表示您的 home 目录(通常作为新的 Bash shell 的起始目录)。

清单 3 演示了使用这些命令是非常容易的。

清单 3. 在 Bash 中使用目录

                    
rb$ pwd
/home/rb
rb$ mkdir temp
rb$ cd temp
rb$ ls
rb$ cd ..
rb$ pwd
/home/rb
rb$ rmdir temp
rb$ ls ..
lost+found    rb          root
rb$ ls /
bin   etc     lib         misc  proc  usr
boot  home    lost+found  mnt   tmp   var
dev   initrd  opt         sbin  sys


    前面的清单中所执行的这些命令都非常的简单。首先,显示出您的当前工作目录。然后,创建一个名为 temp 的新目录,更改到这个新的目录,并列出这个新目录中的内容(因为这个新目录是空的,所以没有显示任何内容)。然后,更改到当前工作目录的父目录,验证已经回到了起始处,然后删除刚创建的临时目录。最后,列出您的 home 目录的父目录(在本例中为 /home)和文件系统的根目录中的内容。

在 Bash 中使用文件

    当在 Bash 中进行工作时,有许多直接和文件打交道的命令。完整列表的内容相当多,但下面是其中一些比较有价值的命令:

    * cp file1 file2 将 file1 复制到 file2。
    * mv file1 file2 将 file1 重命名为 file2。
    * mv filename dirname 将 filename 文件移动到 dirname 目录。
    * less filename 以一种在终端窗口中很容易查看的格式显示文件的内容。
    * file filename 显示文件的最佳猜测类型。
    * cat filename 显示文件的完整内容。
    * head filename 显示文件的前 10 行(可以对确切的数值进行控制)。
    * tail filename 显示文件的最后 10 行(可以对确切的数值进行控制)。
    * diff file1 file2 显示 file1 和 file2 之间的区别,如果存在。
    * grep string filename 根据所指示的字符串搜索目标文件。
    * rm filename 删除该文件。

    清单 4 显示了使用这些命令是非常容易的。请随意打开一个终端,并自己尝试使用这些命令。请记住,如果您想了解更多的信息,只需要查看该命令的手册页面。例如,输入 man cp 以阅读复制命令的手册页面。

清单 4. 在 Bash 中使用文件

                      
rb$ $ cp .bashrc old.bashrc
rb$ diff old.bashrc .bashrc    
rb$ cat ~/.bash_profile
source ~/.bashrc
rb$ cat ~/.bashrc
export PS1='\u\$ '
export DERBY_INSTALL='/opt/Apache/db-derby-10.1.2.1-bin'
export CLASSPATH=$DERBY_INSTALL/lib/derby.jar:$DERBY_INSTALL/lib/derbytools.jar:.
rb$ head -4 /usr/share/dict/web2
A
a
aa
aal
rb$ tail -4 /usr/share/dict/web2
Zythia
zythum
Zyzomys
Zyzzogeton
rb$ grep exuberance /usr/share/dict/web2
exuberance
rb$ file bash-tutorial.zip
bash-tutorial.zip: Zip archive data, at least v2.0 to extract
rb$ file bash-tutorial.xml
bash-tutorial.xml: XML document text

    前面的代码清单中演示的这些文件命令都非常的简单,并且提供了复制文件、查看文件内容、搜索字符串在文件中的出现位置、或了解不同文件的类型的示例。首先,使用复制命令来复制 .bashrc 文件,稍后将对这个文件进行介绍,您可以使用该文件来自定义 Bash shell 的行为和外观。使用 diff 命令来检查两个文件是否相同,如果完全相同,则不会显示出任何区别。接下来,使用 cat 命令显示 .bash_profile 和 .bashrc 文件的内容。我将在下一个部分中更加详细地介绍这两个文件的内容。

    接下来的两个示例是使用 head 和 tail 命令来分别显示文件的开头或结尾的若干行。这些示例使用了标志 -4,这表示仅显示 4 行内容,而不是缺省的 10 行内容。接下来的示例使用 grep 命令在我的计算机上安装的字典中查找字符串 exuberance 的匹配项。最后的两个示例使用 file 命令显示两个不同文件的文件类型。

自定义 Bash

    在本教程前面的内容中,我介绍了一些选项,您可以设置这些选项以更改当前 Bash shell 的行为。对 Bash shell 进行更改的另一种方法是修改环境变量。您可以使用环境变量来修改 Bash 的行为,同时,还可以将相关信息传递到在 Bash 中执行的命令。表 3 列举了一些比较常用的环境变量,您可以在 Bash 中修改或查看这些环境变量。

表 3. 常用的环境变量
变量                              描述
BASH                           BASH 为当前正在运行的 Bash shell 提供了完整的路径。
BASH_VERSION           BASH_VERSION 提供了当前正在运行的 Bash shell 的版本。
CLASSPATH                 CLASSPATH 提供了搜索 Java 类文件或 Java 存档文件的目录列表。
HOME                          HOME 是当前用户的 home 目录。
HOSTNAME                  HOSTNAME 是当前计算机的名称。
LANG                            LANG 是当前的区域设置,它允许根据不同的国家和语言对 shell 进行自定义。
OSTYPE                         OSTYPE 提供了当前操作系统的描述。
PATH                            PATH 是当没有指定完整路径时,搜索命令或应用程序的目录列表。
PS1                               PS1 用作主提示符字符串。
PS2                               PS2 用作从属提示符字符串。
PROMPT_COMMAND    应该在显示 Bash 提示符之前执行这个命令。
PWD                              PWD 是当前工作目录的完整路径。
SHELL                          SHELL 是当前 shell 的完整路径名称。
USER                            USER 是当前用户的登录名称。

    要显示一个环境变量的当前值,可以使用 echo 命令,正如在本教程前面的内容中所演示的,使用该命令来显示 SHELL 变量的值。要设置一个变量的值,使用 $varname=new-value 为变量赋值,然后使用 export $varname 将变量导出到 Bash。在修改环境变量时需加小心。如果您犯了错误,那么可能会使 shell 无法进行响应,或者更糟。通常,您只需修改 PATH、PS1 或相关的环境变量,因为它们用来定位程序或程序组件,或更改 Bash 提示符的外观。

自定义 Bash 提示符

    对 Bash 提示符进行更改,它所提供的强大功能将超出您的想象。您不仅可以更改作为提示符出现的文本,而且您还可以显示当前时间、用户名、计算机名,甚至是当前工作目录。您还可以更改前景和背景颜色,以及显示在终端窗口上的文本的外观。

    要更改提示符的值,您只需修改 PS1 环境变量的值。因此,要将您的提示符修改为显示 I am the Greatest!$ ,可以输入 PS1='I am the Greatest!\$ ' 并按下 Enter (或 Return)。有几点问题值得讨论,即使是在这个简单的示例中。第一点,完整的字符串必须用引号括起来。第二点,需要在字符串结尾加一个空格字符,这样一来,您所输入的任何文本都将与实际提示符分隔开来。当您需要在终端窗口中对以前的命令(及其输出)进行滚动时,这一点非常重要。最后一点,使用转义序列 \$,而不要仅使用一个美元符号。这使得当用户为普通用户时,Bash 显示美元符号 ($),而当用户为超级用户(即 root 用户)时,shell 则将美元符号更改为井号 (#)。如果您需要管理一台计算机,那么这种微妙的变化可能是非常重要的,因为它将帮助提醒您在作为 root 用户的时候要倍加小心。

    Bash 支持几种特殊的转义序列,这样更容易对提示符的外观进行自定义。有关这些序列的完整讨论,请查阅 Bash 的联机手册页面或参见参考资料部分。下面是一些比较常用的序列:

    * \u 扩展为当前用户的用户名。
    * \h 扩展为主机名(直到 DNS 名称中的第一个点号)。
    * \w 扩展为当前工作目录(~ 表示用户的 home 目录)。
    * \t 扩展为以 24 小时时钟格式表示的时间 (HH:MM:SS)。
    * \A 扩展为以 24 小时时钟格式表示的时间 (HH:MM)。
    * \e(ASCII 转义字符)将更多的高级选项传递到终端窗口。
    * \[ 表示非打印字符序列的开始。
    * \] 表示非打印字符序列的结束。

    有了这些序列,现在您可以开始来了解提示符字符串了。例如,在我的 .bashrc 文件中将提示符字符串设置为 PS1='\u\$ ',这将扩展为 rb$,因为我作为普通用户登录到我的计算机中,并且用户名为 rb。一个更复杂的示例是 PS1='[\A][\u@\h:\w]\$ ',它将扩展为(在我的计算机上)[14:14][rb@home:~]$,因为当前的时间为 2:14 p.m.,即我作为用户 rb 登录到名为 home 的计算机上,并且工作于我的 home 目录中。如果您使用不同的终端窗口登录到多台计算机上,那么这类信息是非常有价值的。在每个 Bash shell 中适当地设置了提示符后,您可以快速地查看每台计算机由哪个窗口进行响应。

    另一种快速获得相关信息的好的技术是使用颜色作为标记。如果您曾经在终端窗口中工作过很长时间,并且需要向上滚动以查看某个特殊命令的输出结果,那么您会明白在颜色统一的字符海洋中找出提示符是多么的困难。幸运的是,您可以更改提示符的颜色,这将使它从普通文本中突出显示出来。要说明已提供了颜色代码,可以使用 ASCII 转义序列 \e。实际上,可以在要向 Bash 传递非打印转义序列的任何时候使用这个序列。对于颜色,可以使用 \e[##m 或 \e[##;##m 格式的字符串,其中 ## 字符代表特定的数值。在需要设置文本或背景颜色时,请使用第一种格式。在需要设置文本颜色和表示应该使用特殊特性(如醒目的颜色与浅色)的额外代码时,请使用第二种格式。将这些内容组合到一起,您可以使用 PS1='\e[1;31m[\A]\e[1;34m[\u@\h:\w]\e[0m\$ ' 对以前的提示符自定义颜色。这将使得您的提示符以醒目的红色显示时间,并以醒目的蓝色显示用户名、主机名以及当前工作目录。请注意,在提示符的结尾处将颜色改回了 0(这表示没有指定颜色,或恢复到初始的缺省值)。这将使得您能够从所输入的任何命令、或任何命令的输出结果中清楚地辨认出提示符。

    然而,当使用了这些 ASCII 转义序列后出现了一个复杂的情况,即每次更改提示符时,Bash 会计算您的提示符中到底有多少个字符,并在终端窗口中使用这个值对文本进行换行。因为并不会打印出颜色代码,所以这将影响对 shell 的长度的计算。要避免对提示符字符串中的非打印字符进行统计,可以使用最后介绍的两种转义序列,\[ 和 \],使用它们将不显示在提示符中的文本括起来。尽管有时可以在一个非打印序列中包装多个转义序列,但通常最好是一个非打印序列中只放一个转义序列。有了这一点新的认识,您可以把它合并起来,并正确地构建一个复杂的 Bash 提示符 PS1='\[\e[1;31m\][\A]\[\e[1;34m\][\u@\h:\w]\[\e[0m\]\$ '。

    颜色代码的完整的清单超出了本教程的范围,并且与您所使用的终端的类型密切相关。另外还有一些其他的转义序列,您可以使用它们进一步对终端窗口和 Bash 提示符的行为和外观进行自定义。有关更详细的信息,请浏览 Bash 的联机手册页面或研究参考资料部分。

使用 Bash 初始化文件

    毫无疑问,您并不希望每次启动一个新的 Bash shell 时都去重新设置相应的选项。幸运的是,有几种简单的方式可以用来记录您的自定义信息。当您启动一个新的 Bash 登录 shell(通常发生在打开第一个终端窗口时)时,将读取两个保存了特定自定义信息的文件。第一个文件是 /etc/profile,它允许管理员进行系统范围的自定义,而这些自定义规则将统一地应用于每个用户 Bash 登录 shell。第二个文件是 ~/.bash_profile 或 ~/.profile,这是每个用户自己的自定义文件,它允许您控制对您的 Bash shell 的设置。请记住,波浪符号表示您的 home 目录。此外,如果一个文件名以点号开头,则表示它是隐藏的,这样一来就更不容易意外地移动或删除这些文件。因此,通常许多系统配置文件都以点号开头。

    当您每次启动一个新的 Bash shell(在启动了登录 shell 之后)时,将读取一个新的文件 ~/.bashrc,而不是 ~/.bash_profile 文件。为了尽量避免混淆,推荐的做法是将所有的自定义设置(如设置选项和环境变量)放到您的 ~/.bashrc 文件中,然后在您的登录初始化文件中引用该文件。通过在您的 ~/.bash_profile 文件末尾添加 source ~/.bashrc,您可以很容易地完成这项工作,如清单 4 所示。您还可以进行其他的一些自定义工作,包括更改 Bash 提示符(通过修改 PS1 环境变量的值),更改终端中显示的颜色,甚至说明在注销 Bash 是应该执行的命令(使用 ~/.bash_logout 文件)。

Bash 中的作业控制

    Bash 最强大的功能之一是其协助用户控制不同命令的执行的能力。图 1 显示了基本 UNIX 命令的执行模型。在这个模型中,每条命令都有其标准的机制来处理输入/输出 (IO):

    * STDIN(标准输入)允许程序从 shell 接受输入。
    * STDOUT(标准输出)允许程序将输出传递给 shell。
    * STDERR(标准错误)允许程序将错误信息传递给 shell。

    通常,STDIN 为键盘,您通过它向命令输入相关信息(正如您在 Bash 提示符处所进行的工作),而 STDOUT 和 STDERR 都是屏幕,将在屏幕上显示相应的结果。然而,您可以重新分配这些 IO 机制,以便实现其他的输入/输出方式,例如让一条命令从文件读取信息并将输出写回到文件。


    图 1. 基本命令的执行
Bash 中基本命令的执行

要更改标准的 IO 机制,可以使用表 4 中列出的 Bash 重定向序列。

表 4. 在 Bash 中进行 IO 重定向
命令序列     描述
command < file     command < file 将 STDIN 重定向为读取文件。
command > file     command > file 将 STDOUT 重定向为写入文件。
command >> file     command >> file 将 STDOUT 重定向为追加到文件末尾。
command 2> file     command 2> file 将 STDERR 重定向为写入文件。
command1 | command2     command1 | command2 将 command1 的 STDOUT 连接到 command2 的 STDIN。

    您可以使用表 4 中的最后一项(称为管道)来串联多个命令。使用管道来连接多个命令,这是 UNIX 中 shell 程序开发的一项关键技术,如图 2 所示。在这个模型中,每个命令完成一项简单的任务,并将其执行结果传递给下一个命令,而由该命令来完成另一项简单的任务,依此类推。例如,您可以使用 cat 程序将一个文件的内容通过管道传递到 grep 命令,再由后者将文件中包含给定字符串的每一行通过管道传递到 wc 命令,而该命令可以统计并显示出查找到了多少个这样的字符串。


图 2. 使用管道连接多个命令
在 Bash 中使用管道连接多个命令

异步执行

    到目前为止,所讨论的命令执行都是同步执行,即一次只能执行一条命令。有些时候,命令或程序需要运行很长一段时间。为了避免妨碍 shell 的交互式使用,您可以异步地执行命令。要实现这一点,可以在完整的命令行后添加一个和号符号 (&)。这会告诉 Bash 在后台运行该命令,从而允许您继续在前台使用 shell。清单 5 演示了这种处理方法和其他的作业控制技巧。

清单 5. 演示 Bash 中的作业控制

                    
rb$ grep paper.pdf /var/log/httpd/access.log | wc -l
5
rb$ python demo.py &    
[1] 20451
rb$ jobs
[1]+  Running                 python demo.py &
rb$ fg 1
python demo.py


    清单 5 演示了两种不同的作业控制技巧。第一个技巧是,grep 命令在 Apache Web 服务器中的 access 日志文件中搜索 paper.pdf 字符串。通过管道将这个命令的输出传递到 wc -l 命令,后者将统计在输入文件中出现了多少包含指定字符串的行。因此,您可以使用这个复合命令来统计某个用户通过 Web 站点对 paper.pdf 文件进行了多少次访问。

    第二个技巧是,将长时间运行的 Python 程序作为后台任务来调用。Bash 以异步的方式在后台启动该作业,并且提供了相应的作业标识符。通过使用 jobs 命令,您可以列出所有当前正在运行的命令。在这个示例中,只有一个 Python 程序正在运行,通过使用 fg 命令,您可以将它提升到前台并以同步的方式运行。这里,我仅介绍了 Bash 中的基本作业控制功能。如果您真的想称为一名 shell 专家,那么您需要对该领域的内容进行更深入的研究。
阅读(776) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~