对话 UNIX第 13 部分 另外十种命令行组合.docx
《对话 UNIX第 13 部分 另外十种命令行组合.docx》由会员分享,可在线阅读,更多相关《对话 UNIX第 13 部分 另外十种命令行组合.docx(13页珍藏版)》请在冰点文库上搜索。
对话UNIX第13部分另外十种命令行组合
发现UNIX命令行中更多的快捷方法和强大功能
这个月,我们将介绍UNIX®命令行向导的另外十种秘诀
本文是“对话UNIX”系列文章中的第13部分:
我以前认为13是个不吉利的数字,直到我浏览Internet搜寻这个数字之所以不吉利的原因。
实际上,13这个数字可以说是喜忧参半(请参见参考资料)。
好的方面:
13是元素铝的原子序数,而铝可用于制作各种祭神仪式的奠酒容器;篮球职业运动员WiltChamberlain身着13号球衣(我们都知道,Wilt是非常幸运的);按照某种禁忌转换方式,13是第7个质数,而数字7象征着幸运。
不好的方面:
绞刑架有13级台阶;制造混乱的神“洛基”和犹大,都是第13个到达的;并且无论您怎么对其划分(除以2、3、4、或者6),在餐馆中13个人都很难坐,这可能正是洛基和犹大被认为是局外人的原因。
陪审团最多不超过13个人。
所以,除非您在13号星期五阅读本文,并且在位于MockingbirdLane(这是个历史悠久的地方)1313号的办公楼的第13层,否则都是值得庆幸的。
“对话UNIX”现在是个长满青春痘的青少年了。
本文将介绍十种命令行组合和Shell诀窍,以庆祝本系列文章进入青春期。
恭喜您!
临时设置一个环境变量
环境变量,如EDITOR和TZ,可能影响命令执行的结果。
(前者选择进行文本编辑时所启动的程序;而后者可以指定您的时区。
)通常,您可以在Shell启动文件中设置环境变量,以便对所有的Shell会话产生作用,并且您可以在任何时候使用像 exportTZ=GMT 这样的命令为一个Shell会话更改环境变量的值。
此外,您可以为单个命令临时地修改一个环境变量的值。
只需要在启动命令行的时候设置环境变量以及您希望运行的命令即可。
例如,要为单个命令更改您的首选编辑器,可以在它的前面加上 EDITOR=editor,如下所示:
$printenv
...
EDITOR=vi
...
$EDITOR="pico"lessbigfile
这个组合可以使用 less 对 bigfile 进行分页。
如果您在less中输入 v 以编辑文件,那么将启动 pico 而不是 vi。
下面是另一个实际的使用情况:
$date
SunAug516:
14:
17EDT2007
$TZ="Japan"date
MonAug605:
14:
06JST2007
对TZ进行的临时更改将影响 date 的即时实例解释系统当前日期和时间的方式。
查看您实际正在运行的命令
大量的Shell特性可以影响到如何解释您所输入的命令名。
每种Shell都有一个内置命令的分类;PATH环境变量用于指定搜索的列表和目录;而别名可以作为简写。
要运行一个程序可以使用许多方法,如何了解实际执行的是什么命令呢?
使用Shell内置的 type 命令可以揭示实际的情况。
假设您拥有下面的这些Shell设置:
PATH=/bin:
/usr/bin:
/usr/local/bin
aliasvi=pico
您可以在/usr/bin和/usr/local/bin中找到Perl的副本。
要查明您正使用的是哪个Perl,可以输入 typeperl。
$perl-v
Thisisperl,v5.8.7builtfordarwin-2level
$typeperl
perlis/use/local/bin/perl
$type-aperl
perlis/usr/local/bin/perl
perlis/usr/bin/perl
$type-a-wperl
perl:
command
perl:
command
typeperl 命令显示了如何在命令行中对 perl 命令进行解释。
在这个示例中,/usr/local/bin/perl是实际的扩展结果。
type-a 命令显示了Shell所知道的所有Perl实例,这在很大程度上依赖于PATH变量。
可以针对您常用的其他命令使用 type:
$type-avi
viisanaliasforpico
viis/usr/bin/vi
$type-acd
cdisashellbuiltin
cdis/usr/bin/cd
type 命令显示出,vi 实际上是 pico 的别名。
type 命令还显示出,cd 是一个内置的命令,并且与外部命令/usr/bin/cd是相同的。
使得find命令具有更好的可移植性
去年曾经介绍了许多关于 find 的使用的内容,但是我忽略了其中的一个选项,它使得 find 命令行可以移植到其他操作系统。
通常,UNIX®系统中很少使用带空格的文件名。
然而,在MacOSX和Microsoft®Windows®中常常使用更长的、更具描述性的文件名,并且在UNIX中它们也变得越来越多,这是因为该操作系统不断地积聚更多的桌面特性。
毕竟,将一份报告保存为 2007BusinessPlan 明显要比bizplan07.ooo 好得多。
find 命令使用嵌入的特殊字符列举长文件名,但是,如果您希望将 find 与另一个命令组合使用,那么最安全的方法是,使用NUL字符(而不是空格)分隔列表中的每个文件名。
让我们来了解其中的差异。
我们假设您拥有三个文件夹,其中一个或者多个目录的名称中包含空格:
$ls-1
BusinessPlan2007
ExpenseReport
PicturesfromSpain
如果您对大量的文件运行 find 命令,并且将结果列表传递给 xargs,那么文件名中的空格将会导致错误:
$find.-typef-print|xargsls-1
ls:
./Business:
Nosuchfileordirectory
ls:
./Expense:
Nosuchfileordirectory
ls:
./Pictures:
Nosuchfileordirectory
ls:
2007:
Nosuchfileordirectory
ls:
Plan:
Nosuchfileordirectory
ls:
Report:
Nosuchfileordirectory
ls:
Spain:
Nosuchfileordirectory
ls:
from:
Nosuchfileordirectory
传递给 xargs 的结果是单个字符串 ../BusinessPlan2007./ExpenseReport./PicturesfromSpain。
在缺省情况下,xargs 将使用空格(或者换行符)对输入字符串进行划分,以便产生可以进行操作的一个文件列表。
在这个示例中,因为文件名中包含空格,所以这样做将会产生错误的列表,如前所述。
一种适当的、可移植的技术是使用 find-print0,加上 xargs-0,以便使用NUL字符对文件名进行划分。
下面是这种推荐的方法:
$find.-typef-print0|xargs-0ls-1
./BusinessPlan2007
./ExpenseReport
./PicturesfromSpain
另外,如果您希望预览 xargs 产生的命令,可以添加选项 -p 或者 -t。
-p 选项显示每个合成的命令,并提示您进行确认。
输入大写的或者小写的 y 以便运行命令,输入任何其他的内容可以拒绝该命令。
-t 选项可以在执行每个命令之前将命令回显到 stderr。
更充分地利用find命令
尽管 find 非常有用,但是有两个隐含的设置可能会限制它的结果(并使得您不知所措):
-name 匹配是区分大小写的,并且不会根据符号链接对文件系统进行遍历。
因此,一个以 find-name'*plan*' 开头的命令将忽略名称中包含 Plan 字符串的文件,假设您的home目录中包含名为 music 的符号链接,而它指向装入到/media/music的TB级的存储介质,那么这个命令将不会列出您的符号链接music。
您可以使用 -iname 覆盖区分大小写的匹配,并且您可以使用 -follow 根据符号链接进行遍历。
下面是使用了这两种选项的一个示例:
$aliasls='ls-aF'
$ls-1
bin/
lib/
src/
tomb/
tunes@
$find.-name'*music*'-typef-print
$find.-iname'*music*'-typef-print
$find.-name'*music*'-typef-follow-print
$find.-iname'*music*'-typef-follow-print
./tunes/Muse/OriginOfSymmetry/04HyperMusic.m4a
./tunes/Radiohead/OKComputer/04ExitMusic(ForAFilm).mp3
正如 -F 选项生成的 @ 符号注释所表示的,tunes 是一个符号链接。
要查找名称中包含字符串“music”的任何变体的所有歌曲,您必须使用 -iname*music*。
要遍历到 tunes 所指向的文件系统层次结构,您必须使用 -follow。
为了使得 find 更具可移植性,并且类似于Spotlight的搜索特性,那么应该使用 -print0-follow-iname pattern。
收集许多命令的输出的简单方法
通过使用 > output 和 >> output 修饰符,您可以很容易地捕获一个命令行的输出,其中前者用于创建或者覆盖文件 output,而后者则将内容追加到 output。
您可以组合使用任何修饰符以生成一系列命令的文本,如果您正尝试对系统状态进行快照,这种方法是非常有价值的,例如:
$ps>state.`date'+%F'`
$w>>state.`date'+%F'`
反勾号或反引号操作符(``)可以对命令进行扩展。
在Shell对命令行进行解释时,将执行反勾号之间的命令,并在最终的扩展结果中使用该命令的输出。
在本示例中,参数周围的单引号用于保持参数不变,从而可以避免Shell对 + 和 % 进行解释。
在执行了这两个命令之后,创建了文件 state.YYYY-MM-DD,如 state.2007-08-05,其内容与以下所示类似:
PIDTTYTIMECMD
9997pts/100:
00:
00zsh
10351pts/100:
00:
00ps
17:
56:
04up21days,2:
53,2users,loadaverage:
0.89,0.94,0.91
USERTTYFROMLOGIN@IDLEJCPUPCPUWHAT
adamgoodpts/0c-67-169-182-255Sat170.00s0.37s0.36spine
mstreichpts/1cpe-071-065-224-17:
170.00s0.01s0.00sw
不过,每次输入反勾号操作是非常麻烦的。
您可以使用下面的命令来代替这个序列:
$file=state.`date'+%F'`
$ps>$file
$w>>$file
但是,虽然这样做稍微有效一些,但仍然可能出现错误,因为在第二个或者后续的命令中,很可能使用 > 而不是 >>。
要捕获一系列命令的输出,最简单的方法是使用大括号({})将命令括起来。
${ps;w}>state.`date'+%F'`
ps 命令运行(列出用户当前的进程),然后是 w(它将显示谁正在使用这台计算机),并将收集到的输出保存到一个文件中。
注意:
您还可以在圆括号中嵌入一个命令序列,以得到相同的结果;然而,两者之间有一个重要的区别。
在圆括号中的系列命令将在一个子Shell 中运行,并且不会对当前Shell的状态产生影响。
例如,您可能希望运行这个序列:
${cd$HOME;ls
-1};pwd
它将与下面的命令产生相同的输出:
$(cd$HOME;ls);pwd
大括号中的命令更改了当前Shell的工作目录。
后面的这种技术则无能为力。
是使用组合还是子Shell,这取决于您的目的,尽管子Shell的功能更强大一些,下面将对其进行描述。
子Shell可以为您提供帮助!
尽管通常运行子Shell将聚合的输出通过管道传递给单个命令,但您还可以使用子Shell对命令进行扩展,就像反勾号那样。
然而更有价值的是,子Shell可以包含另一个子Shell,所以还可以进行嵌套扩展。
让我们来看看下面简单的例子。
${ps;w}>state.$(date'+%F')
这个命令与 {ps;w}>state.`date'+%F'` 是相同的。
$() 符号运行圆括号中的命令,然后使用输出来替换自己。
换句话说,$() 可以进行扩展,就像反勾号一样。
然而,与反勾号不同的是,$() 非常复杂,并且甚至可以包括其他 $() 扩展。
下面提供了一些示例:
$(cd$(grepstrike/etc/passwd|cut-f6-d':
');ls)
这个命令在密码文件中搜索用户strike对应的条目,提取其home目录(密码文件中的第6个字段,如果您从0开始数)字段,更改到这个目录,并列出其中的内容。
grep/etc/passwdstrike|cut-f6-d':
' 的输出将在执行任何其他操作之前进行扩展。
下面是另一个示例,这次的用户名来自于 whoami 的结果:
(cd$(grep$(whoami)/etc/passwd|cut-f6-d':
');ls)
因为子Shell有许多用途,所以与组合或者反勾号操作符相比,您可能更喜欢使用它。
不再输入长路径名
有些特性,如PATH和MANPATH环境变量,可以减少输入工作量。
这两个变量分别为搜索可执行文件和man页面定义了一系列目录。
Shell支持另一个搜索路径:
CDPATH。
顾名思义,CDPATH列出了搜索命名目录的目录列表。
让我们看看它是如何工作的。
假设您的home目录中有三个目录,它们分别是tomb、current和personal。
tomb目录中包含旧的工作项目;current目录中包含当前工作的内容;而personal目录中包含您所感兴趣的一些文件和内容。
执行 ls-Rtombcurrentpersonal 命令可以得到与下面所示类似的内容:
$ls-Rtombcurrentpersonal
current:
./../einstein/herbie/
personal:
./../fishing/novel/
tomb:
./../mariner/marvin/voyager/
对于这种结构,如果不使用CDPATH,要更改到任何目录都需要记住文件夹的位置,并输入完全限定的(或者相对的)路径名:
$cd~/tomb/mariner
$cd~/personal/novel
$cd~/current/einstein
为了简化这项任务,可以将CDPATH设置为您所需要的搜索命名目录的目录列表:
$exportCDPATH=.:
~/:
..:
../..:
这是CDPATH的最小设置。
它将按顺序搜索当前目录(.,或者“点”)、您的home目录(~/)、父目录(..,或者“点点”)、父目录的父目录目录(../..)。
最小设置首先搜索本地目录以及附近的一些目录。
在设置了这个CDPATH之后,您可以快速地更改到任何顶层目录:
$pwd
/tmp
$cdcurrent
/home/strike/current
$cdpersonal/fishing
/home/strike/personal/fishing
$cdnovel
/home/strike/personal/novel
$cd/tmp
$cdpersonal/novel
/home/strike/personal/novel
$cd/tmp
$cdnovel
cd:
nosuchfileordirectory:
novel
除最后一个 cd 命令之外,所有命令的参数都在CDPATH中存在匹配的目录。
然而,因为personal目录不在CDPATH中,所以无法找到novel(如果您位于相对路径之外)。
如果您希望搜索personal目录和其他的两个目录,那么可以将它们添加到CDPATH的最后一个冒号的后面,或者根据您所需要的搜索顺序进行添加。
添加三个目录,假设您的Shell启动文件中包含前面的 export 命令:
$exportCDPATH=$CDPATH:
~/current:
~/tomb:
~/personal
现在,您只需要输入希望切换到的目录的名称即可:
$cdcurrent
/home/strike/current
$cd/tmp
$cdeinstein
/home/strike/current/einstein
$cdfishing
/home/strike/personal/fishing
$cdpersonal/novel
/home/strike/personal/novel
与PATH和MANPATH一样,如果CDPATH中的多个条目都包含匹配项,那么在找到第一个匹配项后将停止搜索。
例如,如果您向tomb中添加一个名为 novel 的目录,那么 cdnovel 命令将得到~/tomb/novel。
$mkdir~/tomb/novel
$cd/tmp
$cdnovel
/home/strike/tomb/novel
$cdpersonal/novel
/home/strike/personal/novel
如果其条目中包含唯一的目录名,那么CDPATH是最有效的。
否则,必须输入足够长的路径以进行区别,比如personal/novel。
取得事半功倍的效果
您已经看到了许多示例,说明文本文件在UNIX系统中有着广泛的用途。
大多数系统启动文件都是文本文件,包括Shell脚本、配置文件,当然还包括数据文件。
除了文本编辑器之外,最有价值的实用工具就是翻页工具(pager)、或者允许您逐页浏览文本文件的应用程序。
应用程序 less 是最常用的翻页工具之一,并且它提供了大量的选项以调整它的行为。
事实上,您可以将LESS环境变量设置为相关选项的列表,以便控制less的缺省工作方式。
下面是一组有用的选项:
exportLESS="-Nmsx4"
∙-N 可以显示行号。
∙-m 能够以百分比的形式显示在文件的当前位置。
∙-s 可以将多个空行“压缩”或者减少为单个空行。
∙-x4 可以将制表位设置为四个空格。
请仔细地阅读less的man页面,以便找到对您最有帮助的选项。
从下到上阅读文件
在UNIX系统中,许多文件会不断地增大,直到被截断或者进行存档。
例如,最重要的一些系统处理,如电子邮件传输和远程访问、持续日志记录活动,都会在文件的末尾添加新的条目。
并且是最感兴趣的日志文件的末尾。
如果某个服务崩溃了,那么最后发生的事件将提供最有价值的线索。
有两种方法可以逆序显示文件中的行:
tac(将 cat 反过来)和 tail-r 命令。
$catsmallfile
a
b
c
$tacsmallfile
c
b
a
$tail-rsmallfile
c
b
a
您可能会发现 tac 更加实用一些,因为它将显示整个文件,这与 tail 是不同的,后者将对输出进行截断,只显示若干行的内容。
例如,您可以组合使用 tac 和 less 以创建一个别名,用于对文件进行逆序分页:
$aliasrless="LESSOPEN='|tac%s'less"
$rlesssmallfile
c
b
a
rless 别名临时地将LESSOPEN设置为 |tac%s,这是特定于less的一个环境变量。
这样可以强制使用 tac 对每个文件(%s 是文件名的占位符)进行预处理(所以使用了管道 |)。
下面提供了这个相同技巧的另一种变体,但是它使用了 perl 而不是 tac,在您的系统中可能无法使用这个命令:
LESSOPEN="|perl-e'printreverse(<>)'%s"lesssmall
包含perl的那行命令表示“将所有的输入行读入一个匿名数组((<>)),颠倒元素的顺序,并打印这个新的数组”。
进行新的数学运算
如果您需要计算一个结果,那么并不需要转到一个新的应用程序。
您可以继续在命令行中完成这项任务。
您可以使用 dc(这是一种逆波兰式计算器),或者 bc(这是一种用于数学运算的完整的脚本编程语言)。
或者,如果您需要马上获得答案,那么可以使用命令行和 $(()) 操作符。
$echo$((100/10))
10
$echo$((10**2))
100
Shell并没有提供大量的算术操作符,但是已经足以完成大多数编程任务,包括移位、求余和比较。
还有很多的内容需要学习
“对话UNIX”已经是第13部分了,但是仍然有许多内容需要介绍。
我们需要学习更多的命令和技巧、研究各种各样的相关概念,当然还包括大量的开放源代码软件,以便提高您的工作效率。
还有一点就是,必须克服各种困难。
高年级学生有时会捉弄人,有时的确令人尴尬,但他们相处融洽。
也许我看起来像是在倚老卖老了!
..孩子们相处很融洽,是吧!
感谢您的阅读!
我希望您能够喜欢本专栏。