讲UNIX:您好,shell
UNIX®系统最新颖,最独特的功能之一就是它的命令行 。 只需几次按键,包括一些“胶水”,您就可以使用命令行将有限的UNIX实用程序集组合成无数的即兴数据转换。
例如,要在以当前工作目录为根的文件夹层次结构中查找唯一文件名的列表,可以在shell提示符下键入以下内容:
find . -type f -print | sort | uniq
此命令行结合了三个独立的实用程序:
find
垂直命名目录的深度-在这种情况下,文件系统从开始.
或点 (当前工作目录的简写)-并发出与给定条件匹配的所有条目的名称。 在这里,-type f
指示find
仅发现纯文件。顾名思义,
sort
处理一个列表,并发出一个按字母顺序排序的新列表。-
uniq
(读作“ unique”)扫描列表,比较列表中的相邻元素并删除所有重复项。 例如,假设您有以下列表:清单1.示例列表
Groucho Groucho Chico Chico Groucho Harpo Zeppo Zeppo
uniq
将列表uniq
为以下内容:清单2. uniq命令
Groucho Chico Groucho Harpo Zeppo
但是,如果首先对原始的马克思兄弟列表进行排序(将所有出现的名称重新排序为连续运行),则运行
uniq
产生以下结果:清单3.运行uniq
Chico Groucho Harpo Zeppo
要了解有关find
, sort
和uniq
的广泛功能的更多信息,请参考UNIX系统上每个实用程序的man
页。
数据输入,数据输出,所有数据
独立使用时, find
始终将文件系统的内容作为其输入数据。 但是, sort
和uniq
都需要从标准输入设备 (stdin) 输入或输入数据。 通常,您使用键盘提供stdin:例如,您要在一系列行上键入要排序的数据。
默认情况下,在标准输出设备 (stdout)(通常是您的终端窗口)上find
打印结果。 将sort
和uniq
打印结果都输出到stdout。
为了演示stdin和stdout,请在终端窗口中键入以下文本(假设前导百分号( %
)是您的shell提示符):
清单4. stdin和stdout
% sort
mustache
horn
hat
Control-D
sort
从stdin读取您键入的三行,对其进行排序,然后将结果写入stdout。 图1给出了从命令行运行sort
和大多数UNIX命令行实用程序的概念图。
图1.一个典型的UNIX命令行实用程序从stdin读取并写入stdout
有些实用程序(例如find
)不会从stdin中读取。 相反,他们从系统资源(例如文件系统或系统内核)读取应处理的数据,并将结果写入stdout。 为了可视化find
工作原理,请看下面的图2 。
图2.一些实用程序从系统资源读取数据并将结果写入stdout
除了使用stdin和stdout之外,UNIX命令还可以将错误消息发送到专门用于诊断的特殊出口(根据约定,不是强制性)。 该出口称为标准错误设备 (通常称为stderr)。 图3说明了运行实用程序的简单命令行。
图3. UNIX命令将错误发送到特殊通道,标准错误
如图3所示,大多数UNIX命令从终端读取输入,将结果发送到终端,并向终端打印错误。 默认情况下,除非另外指定,否则终端将是stdin的数据源以及stdout和stderr的目标。
来回路由流量
但是,您可以更改stdin的源以及stdout和stderr的最终目标。 您可以强制stdin从文本文件,设备(例如,连接到计算机的探针)或网络连接中读取。 相比之下,您可以将输出发送到文件,设备或连接。 在所有东西都是文件的UNIX中,一个源或目标与另一个源或目标一样容易使用或产生。
更改流程数据的源和目的地称为重定向 。 您将stdin重定向为从文件或其他源读取数据; 您可以分别重定向stdout和stderr以将数据写入终端窗口以外的其他位置。 在许多情况下,如先前显示的原始find
命令一样,您也可以重定向实用程序,以使用其他实用程序并为其生成数据。 这就是管道 ( |
)的目的。 在命令中,您可以使用管道将多个过程菊花链在一起,将一个命令的数据发送到下一个命令,就像铜管段将水从热水器流到水槽一样。
图4显示了find . -type f -print | sort | uniq
的概念find . -type f -print | sort | uniq
find . -type f -print | sort | uniq
find . -type f -print | sort | uniq
命令。
图4.通过管道链接的三个实用程序的概念模型
find
的标准输出成为uniq
的标准输入; 反过来, uniq
的stdout成为sort
的stdin。 最后, sort
将结果打印到其标准输出设备,该设备仍连接到终端。 命令的stderr未被重定向,因此所有三个实用程序都将错误消息打印到终端。 (来自三个实用程序的错误消息混合在一起,但是消息的顺序将是正确的。)
如有必要,您可以进一步扩展上面显示的管道,并将uniq
的输出重定向到另一个实用程序。 只需在另一个管道上钉一下即可进一步扩展变换。 例如,您可以附加| less
| less
可以使用less
分页输出,或者可以添加| wc -l
| wc -l
查找唯一文件名的数量。 ( wc
是单词计数的首字母缩写; wc
可以计算字符,单词和行数。)
或者,您可以使用>
将整个序列的输出保存到文件中(销毁文件的现有内容,如果有的话)。 您也可以使用>>
将结果附加到现有文件中(如果文件不存在,则创建该文件)。
另一个有用的重定向是<
。 图5显示了如何将stdin重定向为从文件读取。 命令sort
从命名文件中读取单词列表,并将其按字母顺序排列。
图5.重定向标准输入以从文件读取
通常,您需要捕获stdout和stderr。 例如,如果您正在运行大型数据挖掘任务,则可能需要查看临时输出以及在执行过程中发生的任何错误。 您可以使用重定向语法的变体来做到这一点: |&
, >&
, >>&
,分别管道,创建和附加stdout和stderr。 图6说明了如何将stdout和stderr组合为一个输出流。
图6.组合标准输出和标准错误设备
介绍Z壳
大多数现代的UNIX shell(包括Bourne shell( bash
)和Korn shell( ksh
))都支持此处提到的重定向,尽管这两个Shell所需的特定语法可能略有不同。 (有关详细信息,请参阅您的Shell文档。)。
至少25年以来,大多数重定向操作符一直是所有UNIX Shell的一致功能。 但是,大多数这些Shell未能开拓新的领域并探索应用重定向的新方法。 例如,大多数外壳程序只能从单个文件重定向输入,并且您必须使用tee
这样的实用程序将其输出到多个目标。 (与水管工使用的tee结类似, tee
具有一个输入和两个输出。)这是一个使用bash
作为外壳的示例(命令行解释器):
清单5. bash示例
bash$ ls
tellme
bash$ cat tellme
echo Your current login, working directory, and system are...
whoami
pwd
systemname
bash$ bash < tellme |& tee log
Your current login and working directory are...
strike
/home/strike
bash: systemname: command not found
bash$ ls
tellme log
bash$ cat log
Your current login and working directory are
strike
/home/strike
bash: systemname: command not found
尽管UNIX shell是高度专业化的,并且通常使用键盘进行交互使用,但是诸如bash
的shell也可以从文件中读取输入。 (毕竟,stdin只是一个文件。)在上一片段中,短语bash < commands
使bash
执行在文件tellme中找到的命令列表。 短语|&tee log
将bash
的stdout和stderr传递到tee
实用程序,后者将其stdin打印到stdout 和文件日志中。
但是,如果您希望bash
处理多个输入文件怎么办? cat file1 file2 file3 | bash
cat file1 file2 file3 | bash
是一个可行的解决方案,也许是唯一的解决方案,因为bash
不支持bash < file1 < file2 < file3
。
而且, bash
不能将输出重定向到多个目标。 例如,您不能输入类似bighairyscript > ~/log | mail -s "Important stuff" team
的指令bighairyscript > ~/log | mail -s "Important stuff" team
从bash
命令行bighairyscript > ~/log | mail -s "Important stuff" team
。
但一个相对较新的外壳,在Z壳( zsh
;参见相关信息 ),可以处理的相同的命令行内的多个输入和输出重定向。 例如,以下命令将stdout保存在名为log的文件中,并使用电子邮件将其发送给您:
清单6. Z shell
zsh% bash < tellme > log | mail -s "Who you are" 'whoami'
bash: line 4: systemname: command not found
zsh% <log
Your current login, working directory, and system are...
strike
/home/strike
(短语'whoami'
运行命令whoami
并代替该短语插入该命令的结果。这就像在命令行其余部分运行之前运行一个小的shell命令。)
让我们从左到右浏览上一个命令。 bash
命令创建文件日志,并将在tellme中找到的命令的标准输出邮寄给您。 由于stderr未被>
或管道重定向,因此将错误消息打印到stdout。 命令<log
是另一个Z shell快捷方式; 和cat
。 (是的,命令> file
等效于cat > file
。)
Z Shell也可以处理多个输入重定向。 Z Shell命令行cat < file1 < file2 < file3
与cat file1 file2 file3
相同。 诚然,前者的语法比后者更笨拙,并且通常,多标准输出重定向的使用频率更高。 但是,如果您要运行的实用程序不接受多个输入参数,则Z shell的多个输入重定向可以派上用场。
在Z外壳充满了其它新的招数,包括更好的通配符 (通配符匹配),先进的模式匹配,以及广泛的自动完成系统,你有什么最大限度地减少在命令行中键入。 本系列的下两篇文章将进一步探讨Z shell。
Shell技巧
这里有一些强大的命令行组合,这些组合肯定会让您提高工作效率。 这些命令应该在所有shell中运行,而不仅仅是zsh
。
-
使用
tar
创建任何目录的完整副本,包括符号链接:tar cf - /path/to/original | \ (mkdir -p /path/to/copy; cd /path/to/copy; tar xvf -)
第一个
tar
将目录/ path / to / original存档,并将存档文件发送到stdout。 与create(c
)选项一起使用的连字符(-
)指定标准输出。 括号中的命令是一个子shell:该子shell中的命令不会影响当前shell的环境。mkdir -p
创建命名目录,包括任何需要创建的中间目录; 和cd
更改为新目录。 第二个tar
从stdin中读取一个档案,并将其扩展到适当的位置。 与extract(x
)选项一起使用的连字符表示标准输入。 -
要保存命令序列的标准输出并同时查看,请使用
less -O file
。-O
选项将stdin复制到命名file
。 这是一个例子:sort /etc/aliases | less -Osorted
-
如果目录包含成千上万个文件,则您的外壳程序(包括
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
允许您分页浏览结果并将列表保存在名为pages的文件中。 结果是包含字符串“ www.example.com”的文件名列表。
旅程开始
在本文中,您学习了UNIX Shell的基础。 随后的文章将更深入地研究可供您使用的众多命令行工具和技术。 从文件系统到整个局域网,几乎所有信息和系统管理都可以从UNIX命令行高效进行。
敬请关注!
翻译自: https://www.ibm.com/developerworks/aix/library/au-unix-commandline/index.html