在当前工作目录下的文件夹层次结构中查找独特文件名的列表: find . -type f -print | sort | uniq 可使用重定向语法的一些变种来实现该功能:|&, >&, >>& 可分别对 stdout 和 stderr 实现管道、创建、附加功能。 使用 tar 为任何目录创建包括符号链接在内的完整副本: tar cf - /path/to/original | (mkdir -p /path/to/copy; cd /path/to/copy; tar xvf -) 第一个 tar 命令将目录 /path/to/original 进行归档并将归档文件写到 stdout,创建 (c) 选项后面使用的连字符 (-) 表示 stdout。括号中的命令为一个 subshell:subshell 中的命令不会影响当前 shell 的环境。mkdir -p 创建指定目录,包括任何需要创建的中间目录;cd 命令则切换到新目录。第二个 tar 命令从 stdin 读取归档文件并进行展开,展开 (x) 选项后面使用的连字号表示 stdin。 要在保存命令序列的 stdout 同时进行查看,可使用 less -O file 。-O 选项会将 stdin 复制到指定的 file 中。如下例所示:sort /etc/aliases | less -Osorted 如果目录中包含数千个文件,则您的 shell(包括 zsh,取决于文件数目及其名称)可能无法使用通配符匹配来列举出所有文件,因为命令行通常具有一定的字符数限制。因此,类似以下 shell 脚本: foreach i (*) ... end 可能会执行失败。(当超出允许命令行长度时,您可能看到类似 Line length exceeded 的消息。)如果出现此类错误,可使用管道 xargs 实用工具。xargs 命令可从管道中读取数据并为每行读取内容运行指定命令。 例如,如果您要查找服务器上的所有引用 www.example.com 的网页,可使用以下命令行:% find / -name '*html' -print / | xargs grep -l 'www.example.com' / | less -Opages xargs 接收来自 find 的文件名并重复运行 grep -l 以处理每个文件,而不论有多少个文件。(grep -l 在发现一个匹配项之后即打印文件的名称并停止在该文件中的进一步匹配。) less 允许您对结果进行分页并将列表保存在文件指定页中。命令结果为包含字符串“www.example.com”的文件名列表。 下面的命令将在您的 home 目录中查找所有包含单词 Monthly Report 的文本文件: find /home/joe -type f -name '*.txt' -print | xargs grep -l "Monthly Report" 您可以使用符号 ~(波浪符号)引用您的 home 目录。您还可以使用 $HOME 环境变量引用您的 home 目录: $ whoami strike $ echo ~ /Users/strike $ echo $HOME /Users/strike $ !! echo $HOME /Users/strike 最后一个命令 !!(两个感叹号),可能看起来有些奇怪,但它是一种命令历史符号,可以一字不差地重复前面的命令。(许多 Shell 还允许您使用向上箭头键或按 Control+P 来浏览以前的命令列表。) 如上所述,~ 表示您的 home 目录。与之类似的简写形式 ~username 表示 username 的 home 目录。例如,~joe 表示 joe 的 home 目录,所以,要将文件从 joe 的 doc 目录复制到您的 info 目录,您可以输入下面的命令: $ cp ~joe/doc/report.txt ~/info Z Shell 通配符匹配操作符 Z Shell 具有一些独特的和不可多得的通配符匹配操作符。下面是其中一些典型的操作符。 **/ 通配符匹配操作符展开为所有的下级目录,包括当前工作目录。可以将 **/ 看作内置的 find 命令。再次使用 wget 源代码,您可以使用下面的命令查找所有的 Makefile:$ echo **/Makefile Makefile doc/Makefile po/Makefile src/Makefile util/Makefile windows/Makefile 如果您不打算包含当前工作目录,那么只需输入 */**/,如下面的示例所示:$ echo */**/Makefile doc/Makefile po/Makefile src/Makefile util/Makefile windows/Makefile 将输出结果限定为目录: $ ls -d */ ChangeLog-branches/ doc/ po/ src/ util/ windows/ 如下显示了该目录中所有的条目,包括长列表中那些以 .(点)开头的条目。(-a 选项显示了所谓的点文件;-1 选项表示在一列中列出所有的内容;而 -F 选项分别使用 /(正斜杠)和 *(星号)突出表示目录和可执行文件。) ls -1 -a -F 查找名称以点号开头的条目(即 .*)。 ls -a -F .* ./lib 仅查找那些单字母后缀的项目。 ls -1 *.? 仅查找那些 4 个字母后跟点号和单个字符的项目。 ls -1 ????.? 查找这样的项目:以小写字母 a、b 或 c 开头,后面至少跟一个字母,然后可以是任何内容,接着是点号和任何后缀。 ls [a-c]?*.* 要在 Z Shell 中启用命令历史,可以输入: HISTSIZE=500 SAVEHIST=500 在 Shell 中进行了一段时间的工作之后,您只需输入 history 就可以查看命令历史: history ... 781 /bin/ls -d */ 782 /bin/ls -F *(/) 783 /bin/ls -d -F *(/) 784 /bin/ls -d -F */ 785 /bin/ls -d */ 您所运行的每个命令都会分配到一个顺序的数值标识符。您可以使用这个标识符,如 782,来引用完整的命令和命令中的某些部分。要再次运行一个命令,可以输入 !(感叹号)加上命令对应的数值: !785 ChangeLog-branches/ doc/ po/ src/ util/ windows/
如果您希望从一个历史命令中获得特定的参数,可以使用 !(感叹号)来引用这个命令,并提供 :N,其中 0 表示命令名,1 表示第 1 个参数,依此类推。例如,要提取历史日志中命令 782 的第二个参数,可以输入清单 4 中所示的代码。
$ echo !782:2 echo *(/) ChangeLog-branches doc po src util windows $ ls AUTHORS COPYING INSTALL MACHINES AUTHORS COPYING INSTALL MACHINES $ echo !!:3 echo INSTALL $ history -2 788 ls AUTHORS COPYING INSTALL MACHINES 789 echo INSTALL $ echo !788^ echo AUTHORS AUTHORS $ echo !788$ echo MACHINES MACHINES |
命令 history -2
打印出前两个命令。作为快捷方法,您可以使用 ^
(脱字符号)引用命令的第一个参数(而不是命令名本身),并且您可以使用 $
(美元符号)引用历史命令的最后一个参数。您还可以使用范围符号来引用某个范围的参数,如清单 5 所示。
$ echo AUTHORS COPYING INSTALL MACHINES AUTHORS COPYING INSTALL MACHINES $ echo !!:1-2 echo AUTHORS COPYING AUTHORS COPYING |
还有其他的更直接的方法可以用来再次调用历史命令。其中一种方法是搜索历史命令:
$ ls I* $ ls M* $ echo !?M ls INSTALL |
结构 !?M
寻找最近的包含大写字母 M 的历史命令行。
流畅地表达命令行 任务,这是一种基本的 UNIX 技能。但是与 UNIX 进行对话不仅仅只是使用 Shell 提示符,您还必须与各种各样的 UNIX 实用工具进行通信。在 UNIX 中,环境变量保存了 Shell 中的相关设置,并允许您将首选项传播到从命令行启动的所有实用工具中。
有些环境变量称为 Shell 变量,Shell 仅使用这些变量控制其自身的行为。例如,只有 Z Shell 使用 $HISTSIZE
和 $SAVEHIST
管理命令历史,如上所述。可以将 Shell 变量看作相应的设置。
需要对其他的环境变量进行导出、或使得它们全局可用,并将它们复制到从命令行中启动的每个命令的进程空间(即环境)。例如,$HOME
是一个特殊的环境变量,它保存了您的 home 目录的位置。UNIX 登录序列将设置 $HOME
(以及其他的环境变量),然后启动 Shell,而 Shell 反过来使用 $HOME
查找所有的 Shell 启动文件。您所启动的其他应用程序,如 SSH 和 FTP,引用 $HOME
查找 .netrc 文件(用于存储机密的、远程访问的密码)。有些环境变量,如 $HOME
、$PATH
和 $SHELL
,会被所有应用程序使用。其他的环境变量可能专门针对某个应用程序。
要查看当前所有的环境变量,可以输入 printenv
,如清单 6 所示。(根据系统管理员对系统所进行的配置,您系统中的环境变量可能会比本文中所介绍的更多或更少。)
$ printenv
|
$ echo $PWD /Users/strike $ echo $OLDPWD /Local/src/versions/wget/wget-1.9 $ cd $OLDPWD $ echo $PWD /Local/src/versions/wget/wget-1.9 $ echo $OLDPWD /Users/strike |
上面列表中剩下的环境变量都是应用程序特定的。每个环境变量保存了相应的首选项设置,当您启动了与之关联的应用程序后,它可以用于控制该应用程序的工作方式。$PERL5LIB
是 Perl 查找自定义库的搜索路径。ls
命令使用 $CLICOLOR
通过不同的颜色呈现不同类型的文件(目录为蓝色、可执行文件为绿色,等等)。程序的 man 页面中通常包含对自定义应用程序环境变量的说明。
设置环境变量与设置 Shell 变量的方法相同。然而,您必须导出该变量,以使得它全局可用:
$ MYVARIABLE=$HOME/projectX $ export TMPDIR=/tmp/projectX |
前一个命令设置了名为 $MYVARIABLE
的 Shell 变量。(开头的美元符号是 Shell 提示符。您在设置变量时,不用提供这个 $ 符号。然而,当您使用这个变量时,必须使用美元符号,比如 $MYVARIABLE
。)$MYVARIABLE
仅对 Shell 是可见的,因为没有将其导出。要查看所有 Shell 变量的列表,可以输入 set
。set
的输出包括环境变量,因为它们对 Shell 来说也是可用的。
在后面的一个命令中,设置并导出了 $TMPDIR
,因此它对于从 Shell 中启动的所有应用程序都是可用的。GNU Compiler Collection (GCC) 编译器是一个使用 $TMPDIR
的应用程序。$TMPDIR
中所存储的值表示 GCC 用来存放生成的临时文件的位置。
如果您要删除一个环境变量,只需输入 unset
加上变量名即可,如清单 8 所示。
$ set HOME=/Users/strike MYVARIABLE=/Users/strike/projectX TMPDIR=/tmp/projectX ... $ unset MYVARIABLE TMPDIR $ set HOME=/Users/strike .... |
前面的部分主要关注的是如何减少在命令行中的输入。当然,还有许多内容需要学习,因为 Shell 环境非常丰富。然而请记住,功能越强大,生产能力就越大(要对蜘蛛侠说声抱歉,因为修改了原话)。
为了保留以前输入的内容和保存以前的所有设置,UNIX Shell 分别提供了别名和启动文件。别名 是您所创建的快捷方法。每次 Shell 启动时都会读取启动文件,这是保存(和共享)所有 Shell 设置的理想的地方,如 Shell 变量(选项)、环境变量和别名。
别名是一个简短的序列,您可以使用它来代替一个较长的命令。您可以把别名看作是一个命令行的缩写。无需输入:
$ find /home/joe -type f -name '*.txt' -print | xargs grep -l "Monthly Report" |
在命令提示符处,您可以输入已经创建的别名:
$ findreports
|
Shell 减少了工作的复杂程度,它会将 findreports
替换成其扩展形式。要创建 findreports
别名,可以输入:
alias findreports='find $HOME -type f -name "*.txt" -print | xargs grep -l "Monthly Report"' |
必须使用单引号确定每个别名的界限。如果您需要在别名中使用引号,那么可以使用双引号。Z Shell 别名可以包含许多 Shell 基本单位,包括变量、管道、重定向、其他别名和其他 Shell 操作数,如清单 9 所示。
$ alias ll='/bin/ls -l' $ ll -d 2002* drwxrwxr-x 2 www-data www-data 4096 Jan 16 2002 2002-02 drwxrwxr-x 2 www-data www-data 4096 Jan 22 2002 2002-03 drwxrwxr-x 2 www-data www-data 4096 Apr 15 2002 2002-04 drwxrwxr-x 2 www-data www-data 4096 Apr 19 2002 2002-05 ... $ alias lt='ll -t' $ lt -d 2002* drwxrwxr-x 2 www-data www-data 4096 Apr 19 2002 2002-05 drwxrwxr-x 2 www-data www-data 4096 Apr 15 2002 2002-04 drwxrwxr-x 2 www-data www-data 4096 Jan 22 2002 2002-03 drwxrwxr-x 2 www-data www-data 4096 Jan 16 2002 2002-02 $ alias m='pinky | grep mstreicher' $ m mstreicher Martin Streicher ... $ alias snap='pinky >> ~/.pinky' $ snap $ snap $ cat ~/.pinky Login Name TTY Idle When Where mstreicher Martin Streicher pts/0 Jun 18 16:40 cpe-071-065-224-025.nc.res.rr.com Login Name TTY Idle When Where mstreicher Martin Streicher pts/0 Jun 18 16:40 cpe-071-065-224-025.nc.res.rr.com |
别名 ll
表示 /bin/ls,绝对路径不会被别名替换。
当您输入 ll
时,它会被其别名替换,并且附加上剩下的命令行参数。因此,ll -d 2002*
实际上是命令 /bin/ls -l -d 2002*
。别名 lt
表示 ll
加上 -t
标志,以便根据创建时间进行排序。lt
别名扩展为 /bin/ls -l -t -d 2002*
。m
别名包括一个管道。snap
别名使用重定向将命令的输出附加到文件中。
要查看 Shell 中设置的所有别名,只需输入 alias
(不带参数)即可,如清单 10 所示。
$ alias
alias findreports='find $HOME -type f -name "*.txt" -print | xargs grep -l
"Monthly Report"'
alias ll='/bin/ls -l'
alias lt='ll -t'
alias m='pinky | grep mstreicher'
alias snap='pinky >> ~/.pinky'
...
|
如果您要删除别名,只需输入 unalias
加上别名的名称即可。您还可以同时列出多个别名,如清单 11 所示。
$ unalias m snap $ alias alias findreports='find $HOME -type f -name "*.txt" -print | xargs grep -l "Monthly Report"' alias ll='/bin/ls -l' alias lt='ll -t' |
最后,当您经过辛苦的劳动对环境进行了相应的设置之后,您会希望能够保存这些设置,以便下一次继续使用。事实上,您希望 Shell 能够在会话与会话之间、实例与实例之间保持一致,比如当您在工作站上打开了多个终端窗口时。
Shell 包括一些启动文件,当您启动 Shell 时,它们可以用来(重新)初始化您的环境。启动文件可能非常简单(仅包含变量和值的列表),也可能非常复杂(包括自定义逻辑和精心设计的函数)。有些用户会保存多组启动文件,每个项目一组。
Z Shell 使用启动文件 .zshrc 和 .zprofile,这两个文件都位于您的 home 目录中。(其他的 Shell 也具有类似名称的类似文件,您可以阅读 Shell 文档以了解这些细节。有些 Shell 还提供了关闭 文件、或当 Shell 退出时运行的文件。)当启动新的 Shell 时,会将 .zshrc 文件作为信息来源,或对其进行读取和处理;而只有在启动登录 Shell 时才会将 .zprofile 文件作为信息来源。
在您完成对 Shell 的配置之后,请捕获这些设置的快照并将其保存到一个 Shell 启动文件中:
$ set >> $HOME/.zshrc $ alias >> $HOME/.zshrc |
注意:您可能需要编辑所得到的 .zshrc 文件,并删除那些会话特定的变量。