UNIX 和 Linux® 环境下的 Shell 通常可归入两个类别之一,这两个类别基于最初的 UNIX 版本所附带的原始 Shell。这两个类型分别是 Bourne Shell 和 C Shell;后者的独特之处在于其格式和结构类似于 C 编程语言的格式和结构。
Bourne Shell 比 C Shell 更容易使用和理解,但是对于您可能希望在 Shell 编程环境中实现的复杂脚本编程,它可能就不太实用了。Korn Shell 提供了 Bourne Shell 的易用性和附加的作业控制扩展(允许您容易地管理多个后台作业)、命令行编辑和历史记录,以及用于简化编程的附加 C Shell 元素。
Z Shell (zsh) 是在考虑交互式使用而不是编程的情况下设计的,因此它整合了大量显著简化命令使用和运行的功能。这些功能的示例包括更广泛的文件名匹配 (globbing)、用于重定向输入和输出的多个 I/O 流,以及一个可完全自定义的命令行完成系统。
回页首
文件名 globbing 是将文件名或文件规范转换为供命令行(例如,在复制或移动文件时)使用的文件列表的后台过程。基本文件名 globbing 包括使用 ? 来代表单个字符,或使用 * 来代表一个或多个字符。
例如,若要列出所有的 C 源文件,您可以使用 清单 1。
$ ls *.c barney.c betty.c fred.c wilma.c
并且您可以使用字母集合(就像您可能在正则表达式中使用的那样),例如,用于列出具有“c”或“o”扩展名的文件,如清单 2 所示。
$ ls *.[co] barney.c betty.c fred.o barney.o fred.c wilma.c
使用 zsh,相同的通配符仍然有效,但是您还可以使用扩展的 globbing 来指定附加选项。若要启用扩展的 globbing,可以设置EXTENDEDGLOB 环境变量,或者使用: $ setopt extendedglob
。
您现在可以使用诸如 ^ 字符等构造,以显示与给定的文件规范不匹配的所有文件。例如,若要列出与 *.c 规范不匹配的所有文件,可以使用清单 3。
zsh$ ls ^*.c barney.o betty.h fred.h fred.o
表达式 <x-y>
匹配一系列整数。例如,如果您已使用日期对访问日志归档,则可以选择在某个特定日期范围内的所有文件。为实现这点,可以按顺序使用年、月、日来对文件命名,并使用零来补齐空缺。例如,若要列出 2006 年 11 月 3 日和 10 日之间的日志,您可以使用清单 4。
zsh$ ls access<20061103-20061110>.log access20061103.log access20061106.log access20061109.log access20061104.log access20061107.log access20061110.log access20061105.log access20061108.log
您还可以使用类似于正则表达式的组来匹配文件。例如,使用清单 5 来列出所有名为 fred 和 barney 的文件。
zsh$ ls (fred|barney)* barney.c fred.c fred.o barney.o fred.h
通过使用 **/,还可以搜索子目录;该过程是递归的,例如 find
命令,以便您能产生 find
命令的等效结果,例如 $ find . -name "*.c"
。
在 zsh(带扩展的 globbing)中,这可以扩展为: zsh$ ls **/*.c
。
您也可以组合进一步的示例,例如使用清单 6 中的命令来查找子目录中的所有 C 源文件和编译后的目标文件。
zsh$ ls **/*.(c|o) glob/barney.c glob/betty.c glob/fred.o glob/barney.o glob/fred.c glob/wilma.c
最后,zsh 支持许多后缀修饰符。若要获取可执行文件列表,可以在 globbing 表达式结尾使用后缀修饰符 (*)(请参见清单 7)。
zsh$ ls *(*) barney fred
您还可以在 globbing 表达式结尾使用 (x) 来获取可执行文件列表(请参见清单 8)。
zsh$ ls *(x) barney fred
上述列表文件可由文件的所有者执行。大写的 X 将选择可由其他人执行的文件。同样的原理也适用于文件的 R/r(可读取)和 W/w(可写入)模式。
回页首
在大多数 Shell 环境中,您都可以使用基本的进程替换来将一个命令的输出嵌入到另一个命令的输入或参数中。这可以使用反引号运算符来实现(请参见清单 9)。
$ emacs `find . -name "*.html"`
您可以在 zsh 中使用许多选项。最主要的方法是使用 $()
构造。此构造提供对反引号的直接替代,并且它还具有更容易在某些命令组合中嵌入和嵌套的优点。例如,您可以将清单 9 重写为清单 10。
zsh$ emacs $(ls **/*.html)
这里的进程替换运行目录列表组件并返回一个文件名列表,后者又提供给 emacs
命令的参数列表。
另一个有用的构造是 =(list)
结构。当使用此功能时,括号中的元素会生成一个临时文件,并返回该文件的名称。例如,您可以使用清单 11来生成一个文本文件。
zsh$ cat =(print -l tom dick harry) tom dick harry
更有用的是,您可以将它与其他元素组合,以支持更复杂的输出和过滤。例如,您可以使用以下命令(请参见清单 12)来获取与 imapd 和 httpd(IMAP 邮件服务和 Apache http 服务)匹配的进程列表。
zsh$ ps -ax |fgrep -f =(print -l httpd imapd) 406 ?? Ss 0:02.05 /usr/sbin/httpd 426 ?? S 0:01.32 /usr/sbin/httpd 429 ?? S 0:06.42 imapd: sulaco.mcslp.pri [192.168.0.101] appleblog user.appleblog 434 ?? S 0:57.81 imapd: sulaco.mcslp.pri [192.168.0.101] mcarc user.mcarc 435 ?? S 0:00.14 imapd: sulaco.mcslp.pri [192.168.0.101] mlists user.mlists 436 ?? S 0:00.12 imapd: sulaco.mcslp.pri [192.168.0.101] play user.play 437 ?? S 0:01.16 imapd: sulaco.mcslp.pri [192.168.0.101] mc user.mc 507 ?? S 0:01.25 /usr/sbin/httpd
在清单 12 中,print
命令在单独的行上将每个参数输出到一个临时文件。然后 fgrep
使用该文件作为针对进程列表的匹配列表。此临时文件在该命令完成后被删除。
由于该功能从输出创建临时文件,您可以使用它来执行以前要求您自己创建并删除临时文件的功能和序列。例如,若要比较两个不同目录的文件列表,您可以将每个目录中的文件列表输出到一个临时文件,然后使用 diff
命令来比较输出。使用 zsh,在单个命令行上即可实现相同的结果(请参见清单 13)。
zsh$ diff =(ls new) =(ls old) 3d2 < barney.o 9d7 < fred.o
在此示例中,两个被替换的 ls
命令生成一个临时文本文件,然后 diff
命令对该文件进行内联比较。
回页首
与进程替换系统相关的另一个功能是更广泛的重定向系统。在大多数 Shell 中,您都习惯于针对文件执行重定向(请参见清单 14)。
$ crontab <newtab $ ls > filelist
现在使用 zsh,您可以同时重定向到多个输出(请参见清单 15)。
zsh$ ls >listone >listtwo
您还可以从多个流输入(请参见清单 16)。
zsh$ sort <listone <listtwo
管道是隐式的重定向,因此其工作方式大致相同。例如,在任何 Shell 中,您都可以使用 tee
命令来重定向文件和标准输出(请参见清单 17)。
$ ls | tee listone barney barney.c barney.o betty.c betty.h fred fred.c fred.h fred.o wilma.c
在 zsh 中,您可以使用清单 18。
zsh$ ls >fileone |cat barney barney.c barney.o betty.c betty.h fileone fred fred.c fred.h fred.o wilma.c
作为进程替换的扩展,通过使用 <(list) 和 >(list) 构造,您还可以针对另一个命令进行重定向(请参见清单 19)。
zsh$ sort <(ls) <(ls /usr) X11R6 barney barney.c barney.o betty.c betty.h bin fileone fred fred.c fred.h fred.o include lib libexec local sbin share standalone wilma.c
在清单 19 中,您将两个 ls
命令的输出组合为 sort
命令的标准输入,从而输出两个不同目录中的文件的混合和排序列表。
此功能的一个典型使用场合是使用剪切和粘贴来将一个文件中的字段提取并重新组合到另一个文件中。对于普通的 Shell,您可能会使用许多临时文件(请参见清单 20)。
$ cut -f1 fileone >t1 $ cut -f5 filetone >t5 $ paste t1 t5
在 zsh中,您无需临时文件即可完成此任务,如清单 21 所示。
zsh$ paste -d: <(cut -d: -f1 /etc/passwd) <(cut -d: -f5 /etc/passwd)
此外,由于可以容易地嵌套重定向的替换,您可以创建复杂的结构,例如以与源文件不同的顺序组合 passwd 文件中的两个字段、删除注释,然后对它们排序(请参见清单 22)。
zsh$ sort <(egrep -v '^#' <(paste -d: <(cut -d: -f5 /etc/passwd) <(cut -d: -f1 /etc/passwd) ) ) :# mode. At other times this information is handled by one or more of Amavisd User:amavisd Apple Events User:eppc Application Owner:appowner Application Server:appserver ... Xgrid Agent:xgridagent Xgrid Controller:xgridcontroller sshd Privilege separation:sshd
通过按清单 23 所示来查看每个元素,您可以简化清单 22。
- <(cut -d: -f1 /etc/passwd) - Get the first field - <(cut -d: -f5 /etc/passwd) - Get the fifth field - <(paste -d: <(f5) <(f1) ) - Recombine them in a different order - <(egrep -v '^#' <(paste...) - Remove the comments - sort <(egrep ...) - Sort the standard input
回页首
在某些 Shell (包括 zsh)中,您可以通过按 TAB 键来完成文件或命令。让我们使用当前目录作为示例(请参见清单 24)。
zsh$ ls barney betty.c fred fred.o barney.c betty.h fred.c wilma.c barney.o fileone fred.h
使用完成功能,您可以输入文件名的开头:zsh$ cd bar
。然后按 TAB 键并获得完整或部分完成: zsh$ cd barney
.
第二次按 TAB,您将看到可用文件列表(请参见清单 25)。
zsh$ cd barney barney* barney.c barney.o
同样的完成过程也适用于目录和路径。zsh 在完成功能方面做了进一步的优化。
回页首
标准形式的完成功能的局限性在于,它只能在您从命令行上执行输入时完成文件和路径(包括命令)。然而,在其他许多领域,您可能也希望能够完成命令而不必完成所有的输入。例如,源代码控制系统 Subversion 提供了许多二级命令,您在输入其他参数之后另外输入这些命令。例如,若要将更改提交回 Subversion 存储库中,您可以使用 commit 命令:$ svn commit
。或者,若要更新,您可以使用 update 命令: $ svn update
.
但您必须人工执行这些输入。通过使用 zsh 中的自定义完成控制,您可以作为完成过程的一部分来将这些子命令添加到 svn
。完成控制是非常复杂(并且有时非常混淆)的系统,但是其基本原理是相当容易理解的。
完成功能是通过许多命令来控制的,但是最主要的命令为 compctl
。此命令为基本的完成功能提供了一个简单接口。可以全局地应用完成功能(换句话说,就如文件和路径),或者可将其应用于特定的命令。
存在一系列可用的选项和格式,但是为了延续 Subversion 思想,您可以使用 -k
选项来提供一组单词,充当 svn
命令的潜在完成目标(请参见清单 26)。
-k
选项zsh$ compctl -k '(commit checkout update status)' svn
现在,当您在命令开头输入 svn
时,您需要按 TAB 来完成该命令(请参见清单 27)。
zsh$ svn com <TAB> zsh$ svn commit
完成系统包括标准的功能和完成特性——例如,系统上的有效用户、主目录、主机、网络等对象的查找。您还可以自己添加和扩展这些功能来产生自定义的完成结果。
例如,您可以创建一个名为 activeusers 的自定义功能,用于返回用户命令产生的输出: zsh$ function activeusers { reply =(`users`) }
。
您现在可以使用此功能作为另一个命令的完成目标,例如 chat 命令: zsh$ compctl -K activeusers chat
。
现在,当您在命令行上输入 chat
时,可以获得仅返回当前登录用户列表的完成列表。
自定义完成系统的可用选项和可能性实在太多了,无法在此进行一一介绍。有关可用选项的官方文档,请参见参考资料。
回页首
zsh 整合了一系列旨在简化用户与 Shell 环境间交互的功能。相关扩展包括替换命令和针对不同进程重定向信息的更好方法。单凭这些选项就可使您能够将其他 Shell 中需要的许多命令转换为 zsh 中的单个命令行条目。
zsh 与其他 Shell(甚至是诸如 bash 等 Shell 中提供的最新改进)之间的真正区别在于,zsh 能够自定义完成系统以处理文件名和路径以外的更多内容。扩展该功能以支持现有命令的附加参数只是其中一个示例,但是该系统是如此灵活,您几乎可以完成任何命令或命令行元素。
zsh
邮件列表存档:阅读该列表以了解更多的 Z Shell 技巧和提示。zsh
:在 zsh wiki 协作、讨论和分享您的 zsh 专业知识。