[转]linux高手之路:这些人有机会成为Linux高手

1,对英语有亲切感。学起来一点都不费劲。看英文的文章就像看中文的文章一样的人。但是不要说你过了英语几级。我见过一些自称过了英语4级6级的人,他们 的英语并不出色。永远不要埋怨”为什么Linux对中文支持不好?为什么Linux软件没有中文的?“因为中国人在开发这方面做出的贡献太少。本地化不要 指望外国人为我们做贡献。

几乎所有中国的Linux发行版都是骗钱的,毫无开源精神,毫无创新精神,毫无付出精神。你能指望这三无能做出什么好东西来?当然,中国人还是做出了如 stardict、lumaqq这样优秀的开源软件。但是这属于个人行为。另外,stardict、LumaQQ都有中文的!

2,会使用Google搜索引擎。百度只适合老百姓搜家常用,但是对于学术文章,还是Google的搜索有权威性。熟练使用Google才可以找到一些你需要的Linux文章。

3,对QQ没有依赖性。QQ上的菜鸟菜得不是一星半点,他们是那些仅仅听说过Linux就有勇气格式化硬盘的人;QQ上的Linux高手也高不到什么地方 去,他们会的顶多也就是把Linux准确地装到自己的硬盘里能正常使用而已。真正的高手全在IRC上。在QQ上学Linux就是胡闹!哪个Linux玩家 会用一个整天修改登录协议的通讯工具?

4,懂得智慧的提问。不要抓到一个高手,就直接去问人家:“为什么我的Linux不能这样,不能那样?"你错了,不是你的Linux不能这样,不能那样,是你不能把你的Linux整成那样而已。永远不要去埋怨计算机程序,从某种意义上说,它比某些人的大脑要精密很多。

想提问也要先把Linux的一些概念搞清楚。很多人张口就Linux 9.0,请你们注意,只有Suse Linux有9.0,Mandriva Linux有9.0, Red Hat Linux有9.0 ,但是Linux kernel 只有 2.x.y,没有9.0。请学习基础知识再说话,以免露怯。

5,学会自学。绝大多数菜鸟问题,互联网上 已经满是答案。你根本不需要浪费高手的生命去给你解释那些你可能一无所知,但是人家已经解释了1000遍的问题。谁都有烦的时候,你本来水平就次,还怨别 人不教?Linux,任何人都是自学成才的,任何人在学习的道路上都是曲折漫长的,你想走捷径也不要去拖别人的后腿——上学还得交学费吧?哪个高手一天免费在QQ上伺候菜鸟?还随叫随到?你去问问教委,9年义务教育有这样的服务么?

6,不埋怨操作系统不好。如果你想用Linux,但是又觉得它这样不好,那样不好,请你干脆回去用Windows。尤其在请教高手问题的时候,不要带着对Linux嘲讽的字眼。那能说明什么问题?那只能说明:一是你自己Linux技术不到位,二是你人品不到位。

Linux作为一个操作系统有自己的特征,Windows作为一个操作系统也有自己的特征。不要用Windows的眼光去比较两个操作系统。如果你用那样 的标准去看问题,只能说明你根本不懂计算机——你也别再说你是大学计算机系毕业的,不然那些自学成才的高手会笑得鼻血喷到美国去。

[转]UNIX 技巧: UNIX 高手的另外 10 个习惯 成为 UNIX 命令行高手

推荐你先看看本文的上篇:UNIX 高手的 10 个习惯 克服不良的 UNIX 使用模式

John Fronckowiak, 总裁, IDC Consulting Inc.

2008 年 7 月 24 日

作为 Michael Stutz 优秀文章的后续,本文将提供另外 10 个改进您的 UNIX® 命令行效率的好习惯。了解常见错误和克服它们的方法,并确切了解为何值得采用这 10 个 UNIX 习惯。

让我们面对现实吧:坏习惯很难改变。但是您已经熟悉的习惯可能更难克服。有时,重新审视某些事情可能让您遇到“啊哈,我没想到它能做到这一点!”的时刻。在 Michael Stutz 的优秀文章“UNIX 高手的 10 个习惯”的基础上,本文将提供另外 10 个 UNIX 命令行命令、工具和技术,可以使您成为更高效的 UNIX 命令行高手。

您应当采纳的其他 10 个好习惯包括:

  • 使用文件名自动完成功能 (file name completion)。
  • 使用历史扩展。
  • 重用以前的参数。
  • 使用 pushdpopd 管理目录导航。
  • 查找大型文件。
  • 不使用编辑器创建临时文件。
  • 使用 curl 命令行实用工具。
  • 最有效地利用正则表达式。
  • 确定当前用户。
  • 使用 awk 处理数据。
常用首字母缩写词

  • MB:兆字节
  • HTTP:超文本传输协议
  • HTTPS:HTTP over Secure Sockets Layer
  • FTP:文件传输协议
  • FTPS:FTP over Secure Sockets Layer
  • LDAP:轻型目录访问协议

使用文件名完成

如果不需要在命令提示符处键入长的、令人费解的文件名,这是不是很棒呢?的确,您不需要这样做。相反,您可以配置最流行的 UNIX Shell 以使用文件名完成。该功能在各个 Shell 中的工作方式略有不同,因此我将向您展示如何在最流行的 Shell 中使用文件名完成。文件名完成使您可以更快地输入并避免错误。懒惰?也许吧。效率更高?当然!

我正在运行哪种 Shell?

如果您不知道目前使用的是哪一种 Shell,会怎么样?虽然这个诀窍不是另外 10 个好习惯的正式组成部分,但它仍然很有用。如清单 1 所示,您可以使用 echo $0ps -p $$ 命令显示您正在使用的 Shell。对于我来说,运行的是 Bash Shell。
清单 1. 确定您的 Shell

$ echo $0
-bash
$ ps –p $$
PID TTY           TIME CMD
6344 ttys000    0:00.02 –bash

C Shell

C Shell 支持最直接文件名完成功能。设置 filec 变量可启用该功能。(您可以使用命令 set filec。)在您开始键入文件名后,可以按 Esc 键,Shell 将完成文件名,或完成尽可能多的部分。例如,假设您拥有名为 file1、file2file3 的文件。如果您键入 f,然后按 Esc 键,将填充 file,而您必须键入 123 来完成相应的文件名。

Bash

Bash Shell 也提供了文件名完成,但使用 Tab 键代替 Esc 键。您在 Bash Shell 中不需要设置任何选项即可启用文件名完成,该选项是缺省设置的。Bash 还实现了其他功能。键入文件名的一部分后,按 Tab 键,如果有多个文件满足您的请求,并且您需要添加文本以选择其中一个文件,那么您可以多按 Tab 键两次,以显示与您目前键入的内容相匹配的文件的列表。使用之前名为 file1、file2file3 的文件示例,首先键入 f。当您按一次 Tab 键时,Bash 完成 file;再按一次 Tab 键时,将展开列表 file1 file2 file3

Korn Shell

对于 Korn Shell 用户,文件名完成取决于 EDITOR 变量的值。如果 EDITOR 设置为 vi,那么您键入部分名称,然后按 Esc 键,后跟反斜杠 (\) 字符。如果 EDITOR 设置为 emacs,那么您键入部分名称,然后按两次 Esc 键以完成文件名。

使用历史扩展

如果您为一系列命令使用相同的文件名,会发生什么情况?当然,有一种快捷方式可以快速获得您上次使用的文件名。如清单 2 所示,!$ 命令返回前一个命令使用的文件名。从文件 this-is-a-long-lunch-menu-file.txt 中搜索单词 pickles 的出现位置。搜索结束后,使用 vi 命令来编辑 this-is-a-long-lunch-menu-file.txt 文件,而不需要重新键入文件名。您使用感叹号 (!) 来访问历史,然后使用美元符号 ($) 返回前一命令的最后字段。如果您反复用到长文件名,那么这是一个非常好的工具。
清单 2. 使用 !$ 获得前一个命令使用的文件名

$ grep pickles this-is-a-long-lunch-menu-file.txt
pastrami on rye with pickles and onions
$ vi !$

重用以前的参数

!$ 命令返回某个命令使用的上一个文件名参数。但如果某个命令使用多个文件名,而您只希望重用其中一个文件名,该如何做?!:1 操作符返回某个命令使用的第一个文件名。清单 3 中的示例显示可以如何将此操作符与 !$ 运算符组合使用。在第一个命令中,将一个文件重新命名为更有意义的名称,但为了保持原始文件名可用,创建了一个符号链接。重新命名文件 kxp12.c 以提高可读性,然后使用 link 命令来创建到原始文件名的符号链接,以防在其他位置使用该文件名。!$ 操作符返回 file_system_access.c 文件名,而 !:1 操作符返回 kxp12.c 文件名,该文件名是上个命令的第一个文件名。
清单 3. 组合使用 !$ 和 !:1

$ mv kxp12.c file_system_access.c
$ ln –s !$ !:1

使用 pushd 和 popd 管理目录导航

UNIX 支持各种目录导航工具。我最喜欢的两款提高工作效率的工具是 pushdpopd。您当然了解 cd 命令用于更改您的当前目录。如果您要在多个目录中导航,但希望能够快速返回某个位置,该如何做?pushdpopd 命令创建一个虚拟目录堆栈,pushd 命令用来更改您的当前目录并将其存储在堆栈中,而 popd 命令用来从堆栈的顶部移除目录并使您返回该位置。您可以使用 dirs 命令来显示当前目录堆栈,而不会压入或弹出新目录。清单 4 显示如何使用 pushdpopd 命令在目录树中快速导航。
清单 4. 使用 pushd 和 popd 在目录树中导航

$ pushd .
~ ~
$ pushd /etc
/etc ~ ~
$ pushd /var
/var /etc ~ ~
$ pushd /usr/local/bin
/usr/local/bin /var /etc ~ ~
$ dirs
/usr/local/bin /var /etc ~ ~
$ popd
/var /etc ~ ~
$ popd
/etc ~ ~
$ popd
~ ~
$ popd

pushdpopd 命令还支持使用参数处理目录堆栈。使用 +n -n 参数,其中 n 是一个数字,您可以向左或向右移动堆栈,如清单 5 所示。
清单 5. 旋转目录堆栈

$ dirs
/usr/local/bin /var /etc ~ ~
$ pushd +1
/var /etc ~ ~ /usr/local/bin
$ pushd -1
~ /usr/local/bin /var /etc ~

查找大型文件

是否需要找出您的所有空闲磁盘空间被什么占用了?您可以使用以下几个工具来管理您的存储设备。如清单 6 所示,df 命令为您显示每个可用卷上已使用的块的总数,以及空闲空间的百分比。
清单 6. 确定卷的使用情况

$ df
Filesystem                            512-blocks      Used  Available Capacity  Mounted on
/dev/disk0s2                           311909984 267275264   44122720    86%    /
devfs                                        224       224          0   100%    /dev
fdesc                                          2         2          0   100%    /dev
map -hosts                                     0         0          0   100%    /net
map auto_home                                  0         0          0   100%    /home

是否希望查找大型文件?使用 find 命令时附带 -size 参数。清单 7 显示了如何使用 find 命令来查找大于 10MB 的文件。请注意,-size 参数以 KB 为单位计量大小。
清单 7. 查找大于 10MB 的所有文件

$ find / -size +10000k –xdev –exec ls –lh {}\;

不使用编辑器创建临时文件

以下是一个简单示例:您需要快速创建一个简单临时文件,但不希望启动您的编辑器。使用带有 > 文件重定向操作符的 cat 命令。如清单 8 所示,使用不带文件名的 cat 命令只回显向标准输入键入的任何内容;> 重定向将该输入捕获到指定的文件中。请注意,您在结束键入时必须提供文件结束字符,通常为 Ctrl-D。
清单 8. 快速创建临时文件

$ cat > my_temp_file.txt
This is my temp file text
^D
$ cat my_temp_file.txt
This is my temp file text

需要执行相同操作,但是附加到现有文件而不是创建新文件。如清单 9 所示,改用 >> 操作符。>> 文件重定向操作符向现有文件附加内容。
清单 9.快速向文件附加内容

$ cat >> my_temp_file.txt
More text
^D
$ cat my_temp_file.txt
This is my temp file text
More text

使用 curl 命令行实用工具

我是否可以从命令行访问 Web?你疯了吗?没有,这就是 curl 的用途!curl 命令使您可以使用 HTTP、HTTPS、FTP、FTPS、Gopher、DICT、TELNET、LDAP 或 FILE 协议从服务器检索数据。如清单 10 所示,我可以使用 curl 命令从美国国家气象局了解我所在位置(纽约州布法罗市)的当前天气状况。当与 grep 命令组合使用时,我可以检索布法罗市的天气状况。使用 -s 命令行选项来禁止 curl 处理输出。
清单 10. 使用 curl 检索当前天气状况

$ curl –s http://www.srh.noaa.gov/data/ALY/RWRALY | grep BUFFALO
BUFFALO        MOSUNNY   43  22  43 NE13      30.10R

清单 11 所示,您也可以使用 curl 命令来下载 HTTP 托管的文件。使用 -o 参数来指定保存输出的位置。
清单 11. 使用 curl 下载 HTTP 承载的文件

$ curl -o archive.tar http://www.somesite.com/archive.tar

这实际上只是您使用 curl 命令可以完成的操作的提示。您只需在命令提示符处键入 man curl 显示 curl 命令的完整使用信息,就可以开始了解更多内容。

最有效地利用正则表达式

大量 UNIX 命令使用正则表达式作为参数。从技术角度而言,正则表达式 是表示某种模式的字符串(也就是说,由字母、数字和符号组成的字符序列),用于定义零或更长的字符串。正则表达式使用元字符(例如,星号 [*] 和问号 [?])来匹配其他字符串的部分或全部内容。正则表达式不一定包含通配符,但通配符可以使正则表达式在搜索模式和处理文件时发挥更大的作用。表 1 显示了一些基本正则表达式序列。
表 1. 正则表达式序列

序列 说明
脱字符 (^) 匹配出现在行首的表达式,例如 ^A
美元符号 ($) 匹配出现在行末的表达式,例如 A$
反斜杠 (\) 取消下一个字符的特殊含义,例如 \^
方括号 ([]) 匹配括起来的任一字符,例如 [aeiou](使用连字符 [-] 表示范围,例如 [0-9])。
[^ ] 匹配除括起来字符以外的任一字符,例如 [^0-9]
句点 (.) 匹配除行尾之外的任意单个字符
星号 (*) 匹配零个或多个前驱字符或表达式
\{x,y\} 匹配出现过 xy 个和前面相同的内容
\{x\} 精确匹配出现过 x 个和前面相同的内容
\{x,\} 匹配出现过 x 个或更多和前面相同的内容

清单 12 显示了与 grep 命令一起使用的一些基本正则表达式。
清单 12. 使用正则表达式和 grep

$ # Lists your mail
$ grep '^From: ' /usr/mail/$USER
$ # Any line with at least one letter
$ grep '[a-zA-Z]'  search-file.txt
$ # Anything not a letter or number
$ grep '[^a-zA-Z0-9] search-file.txt
$ # Find phone numbers in the form 999-9999
$ grep '[0-9]\{3\}-[0-9]\{4\}' search-file.txt
$ # Find lines with exactly one character
$ grep '^.$' search-file.txt
$ #  Find any line that starts with a period "."
$ grep '^\.' search-file.txt
$ # Find lines that  start with a "." and 2 lowercase letters
$ grep '^\.[a-z][a-z]' search-file.txt

有大量书籍专门讲述正则表达式。有关命令行正则表达式的深入描述,建议您阅读 developerWorks 文章“对话 UNIX,第 9 部分:正则表达式。”

确定当前用户

有时,您可能希望确定某个特定用户是否运行过您的管理脚本。为找出答案,您可以使用 whoami 命令来返回当前用户的名称。清单 13 显示了独自运行的 whoami 命令;清单 14 显示了使用 whoami 确保当前用户不是根用户的 Bash 脚本的摘录。
清单 13. 从命令行使用 whoami

$ whoami
John

清单 14. 在脚本中使用 whoami

if [ $(whoami) = "root" ]
then
   echo "You cannot run this script as root."
   exit 1
fi

使用 awk 处理数据

awk 命令似乎始终处在 Perl 的阴影下,但它对于简单、基于命令行的数据处理来说是一个快速、实用的工具。清单 15 显示了如何开始使用 awk 命令。若要获取文件中每行文本的长度,请使用 length() 函数。若要查看字符串 ing 是否出现在文件文本中,请使用 index() 函数,该函数返回 ing 首次出现的位置,这样您就可以使用它来进行进一步的字符串处理。若要 tokenize(也就是说,将一行拆分为单词长度的片段)某个字符串,请使用 split() 函数。
清单 15. 基本 awk 处理

$ cat text
testing the awk command
$ awk '{ i = length($0); print i }' text
23
$ awk '{ i = index($0,”ing”); print i}' text
5
$ awk 'BEGIN { i = 1 } { n = split($0,a," "); while (i <= n) {print a[i]; i++;} }' text
testing
the
awk
command

打印文本文件中的指定字段是一项简单的 awk 任务。在清单 16 中,sales 文件包含每个销售人员的姓名,后跟每月销售数字。您可以使用 awk 命令来快速获得每个月的销售总额。缺省情况下,awk 将每个以逗号分隔的值视为不同的字段。您使用 $n 操作符来访问每个字段。
清单 16. 使用 awk 对数据进行汇总

$cat sales
Gene,12,23,7
Dawn,10,25,15
Renee,15,13,18
David,8,21,17
$ awk -F, '{print $1,$2+$3+$4}' sales
Gene 42
Dawn 50
Renee 46
David 46

awk 命令可以很复杂并应用于广泛的情景中。若要更完整地学习 awk 命令,请从命令 man awk 开始,并参阅参考资料部分提供的资源。

结束语

成为命令行高手需要进行一些实践。按照相同的方式处理问题很简单,因为您已经习惯了。扩展您的命令行资源可以显著提高您的工作效率,并促使您朝着 UNIX 命令行高手的方向前进!

参考资料

学习

讨论

关于作者

John Fronckowiak 是 IDC Consulting Inc. 的总裁兼创始人,他还是曼达尔大学成人和继续教育学院计算机信息系统的临床助理教授。他还撰写了几本关于 Web 应用程序开发、编程、数据库设计和开发以及网络方面的书籍和多篇文章。

[转]UNIX 高手的 10 个习惯 克服不良的 UNIX 使用模式

顺便说一下,这里还有本文的下篇:UNIX 技巧: UNIX 高手的另外 10 个习惯

引言

当您经常使用某个系统时,往往会陷入某种固定的使用模式。有时,您没有养成以尽可能最好的方式做事的习惯。有时,您的不良 习惯甚至会导致出现混乱。纠正此类缺点的最佳方法之一,就是有意识地采用抵制这些坏习惯的好习惯。本文提出了 10 个值得采用的 UNIX 命令行习惯——帮助您克服许多常见使用怪癖,并在该过程中提高命令行工作效率的好习惯。下面列出了这 10 个好习惯,之后对进行了更详细的描述。

采用 10 个好习惯

要采用的十个好习惯为:

  1. 在单个命令中创建目录树
  2. 更改路径;不要移动存档
  3. 将命令与控制操作符组合使用
  4. 谨慎引用变量
  5. 使用转义序列来管理较长的输入
  6. 在列表中对命令分组
  7. find 之外使用 xargs
  8. 了解何时 grep 应该执行计数——何时应该绕过
  9. 匹配输出中的某些字段,而不只是对行进行匹配
  10. 停止对 cat 使用管道

在单个命令中创建目录树

清单 1 演示了最常见的 UNIX 坏习惯之一:一次定义一个目录树。
清单 1. 坏习惯 1 的示例:单独定义每个目录树

~ $ mkdir tmp
~ $ cd tmp
~/tmp $ mkdir a
~/tmp $ cd a
~/tmp/a $ mkdir b
~/tmp/a $ cd b
~/tmp/a/b/ $ mkdir c
~/tmp/a/b/ $ cd c
~/tmp/a/b/c $

使用 mkdir-p 选项并在单个命令中创建所有父目录及其子目录要容易得多。但是即使对于知道此选项的管理员,他们在命令行上创建子目录时也仍然束缚于逐步创建每级子目录。花时间有意识地养成这个好习惯是值得的:
清单 2. 好习惯 1 的示例:使用一个命令来定义目录树

~ $ mkdir -p tmp/a/b/c

您可以使用此选项来创建整个复杂的目录树(在脚本中使用是非常理想的),而不只是创建简单的层次结构。例如:
清单 3. 好习惯 1 的另一个示例:使用一个命令来定义复杂的目录树

~ $ mkdir -p project/{lib/ext,bin,src,doc/{html,info,pdf},demo/stat/a}

过去,单独定义目录的唯一借口是您的 mkdir 实现不支持此选项,但是在大多数系统上不再是这样了。IBM、AIX®、mkdir、GNU mkdir 和其他遵守单一 UNIX 规范 (Single UNIX Specification) 的系统现在都具有此选项。

对于仍然缺乏该功能的少数系统,您可以使用 mkdirhier 脚本(请参见参考资料),此脚本是执行相同功能的 mkdir 的包装:

~ $ mkdirhier project/{lib/ext,bin,src,doc/{html,info,pdf},demo/stat/a}

更改路径;不要移动存档

另一个不良的使用模式是将 .tar 存档文件移动到某个目录,因为该目录恰好是您希望在其中提取 .tar 文件的目录。其实您根本不需要这样做。您可以随心所欲地将任何 .tar 存档文件解压缩到任何目录——这就是 -C 选项的用途。在解压缩某个存档文件时,使用 -C 选项来指定要在其中解压缩该文件的目录:
清单 4. 好习惯 2 的示例:使用选项 -C 来解压缩 .tar 存档文件

~ $ tar xvf -C tmp/a/b/c newarc.tar.gz

相对于将存档文件移动到您希望在其中解压缩它的位置,切换到该目录,然后才解压缩它,养成使用 -C 的习惯则更加可取——当存档文件位于其他某个位置时尤其如此。


Back to top

将命令与控制操作符组合使用

您可能已经知道,在大多数 Shell 中,您可以在单个命令行上通过在命令之间放置一个分号 (;) 来组合命令。该分号是 Shell 控制操作符, 虽然它对于在单个命令行上将离散的命令串联起来很有用,但它并不适用于所有情况。例如,假设您使用分号来组合两个命令,其中第二个命令的正确执行完全依赖 于第一个命令的成功完成。如果第一个命令未按您预期的那样退出,第二个命令仍然会运行——结果会导致失败。相反,应该使用更适当的控制操作符(本文将描述 其中的部分操作符)。只要您的 Shell 支持它们,就值得养成使用它们的习惯。

仅当另一个命令返回零退出状态时才运行某个命令

使用 && 控制操作符来组合两个命令,以便仅当 第一个命令返回零退出状态时才运行第二个命令。换句话说,如果第一个命令运行成功,则第二个命令将运行。如果第一个命令失败,则第二个命令根本就不运行。例如:
清单 5. 好习惯 3 的示例:将命令与控制操作符组合使用

~ $ cd tmp/a/b/c && tar xvf ~/archive.tar

在此例中,存档的内容将提取到 ~/tmp/a/b/c 目录中,除非该目录不存在。如果该目录不存在,则 tar 命令不会运行,因此不会提取任何内容。

仅当另一个命令返回非零退出状态时才运行某个命令

类似地,|| 控制操作符分隔两个命令,并且仅当第一个命令返回非零退出状态时才运行第二个命令。换句话说,如果第一个命令成功,则第二个命令不会运行。如果第一个命令失败,则第二个命令才会 运行。在测试某个给定目录是否存在时,通常使用此操作符,如果该目录不存在,则创建它:
清单 6. 好习惯 3 的另一个示例:将命令与控制操作符组合使用

~ $ cd tmp/a/b/c || mkdir -p tmp/a/b/c

您还可以组合使用本部分中描述的控制操作符。每个操作符都影响最后的命令运行:
清单 7. 好习惯 3 的组合示例:将命令与控制操作符组合使用

~ $ cd tmp/a/b/c || mkdir -p tmp/a/b/c && tar xvf -C tmp/a/b/c ~/archive.tar

Back to top

谨慎引用变量

始终要谨慎使用 Shell 扩展和变量名称。一般最好将变量调用包括在双引号中,除非您有不这样做的足够理由。类似地,如果您直接在字母数字文本后面使用变量名称,则还要确保将该变 量名称包括在方括号 ([]) 中,以使其与周围的文本区分开来。否则,Shell 将把尾随文本解释为变量名称的一部分——并且很可能返回一个空值。清单 8 提供了变量的各种引用和非引用及其影响的示例。
清单 8. 好习惯 4 的示例:引用(和非引用)变量

~ $ ls tmp/
a b
~ $ VAR="tmp/*"
~ $ echo $VAR
tmp/a tmp/b
~ $ echo "$VAR"
tmp/*
~ $ echo $VARa

~ $ echo "$VARa"

~ $ echo "${VAR}a"
tmp/*a
~ $ echo ${VAR}a
tmp/a
~ $

Back to top

使用转义序列来管理较长的输入

您或许看到过使用反斜杠 (\) 来将较长的行延续到下一行的代码示例,并且您知道大多数 Shell 都将您通过反斜杠联接的后续行上键入的内容视为单个长行。然而,您可能没有在命令行中像通常那样利用此功能。如果您的终端无法正确处理多行回绕,或者您的 命令行比通常小(例如在提示符下有长路经的时候),反斜杠就特别有用。反斜杠对于了解键入的长输入行的含义也非常有用,如以下示例所示:
清单 9. 好习惯 5 的示例:将反斜杠用于长输入

~ $ cd tmp/a/b/c || \
> mkdir -p tmp/a/b/c && \
> tar xvf -C tmp/a/b/c ~/archive.tar

或者,也可以使用以下配置:
清单 10. 好习惯 5 的替代示例:将反斜杠用于长输入

~ $ cd tmp/a/b/c \
>                 || \
> mkdir -p tmp/a/b/c \
>                    && \
> tar xvf -C tmp/a/b/c ~/archive.tar

然而,当您将输入行划分到多行上时,Shell 始终将其视为单个连续的行,因为它总是删除所有反斜杠和额外的空格。

注意:在大多数 Shell 中,当您按向上箭头键时,整个多行输入将重绘到单个长输入行上。


Back to top

在列表中对命令分组

大多数 Shell 都具有在列表中对命令分组的方法,以便您能将它们的合计输出向下传递到某个管道,或者将其任何部分或全部流重定向到相同的地方。您一般可以通过在某个 Subshell 中运行一个命令列表或通过在当前 Shell 中运行一个命令列表来实现此目的。

在 Subshell 中运行命令列表

使用括号将命令列表包括在单个组中。这样做将在一个新的 Subshell 中运行命令,并允许您重定向或收集整组命令的输出,如以下示例所示:
清单 11. 好习惯 6 的示例:在 Subshell 中运行命令列表

~ $ ( cd tmp/a/b/c/ || mkdir -p tmp/a/b/c && \
> VAR=$PWD; cd ~; tar xvf -C $VAR archive.tar ) \
> | mailx admin -S "Archive contents"

在此示例中,该存档的内容将提取到 tmp/a/b/c/ 目录中,同时将分组命令的输出(包括所提取文件的列表)通过邮件发送到地址 admin

当您在命令列表中重新定义环境变量,并且您不希望将那些定义应用于当前 Shell 时,使用 Subshell 更可取。

在当前 Shell 中运行命令列表

将命令列表用大括号 ({}) 括起来,以在当前 Shell 中运行。确保在括号与实际命令之间包括空格,否则 Shell 可能无法正确解释括号。此外,还要确保列表中的最后一个命令以分号结尾,如以下示例所示:
清单 12. 好习惯 6 的另一个示例:在当前 Shell 中运行命令列表

~ $ { cp ${VAR}a . && chown -R guest.guest a && \
> tar cvf newarchive.tar a; } | mailx admin -S "New archive"

Back to top

在 find 之外使用 xargs

使用 xargs 工具作为筛选器,以充分利用从 find 命令挑选的输出。find 运行通常提供与某些条件匹配的文件列表。此列表被传递到 xargs 上,后者然后使用该文件列表作为参数来运行其他某些有用的命令,如以下示例所示:
清单 13. xargs 工具的经典用法示例

~ $ find some-file-criteria some-file-path | \
> xargs some-great-command-that-needs-filename-arguments
                

然而,不要将 xargs 仅看作是 find 的辅助工具;它是一个未得到充分利用的工具之一,当您养成使用它的习惯时,将会希望进行所有试验,包括以下用法。

传递空格分隔的列表

在最简单的调用形式中,xargs 就像一个筛选器,它接受一个列表(每个成员分别在单独的行上)作为输入。该工具将那些成员放置在单个空格分隔的行上:
清单 14. xargs 工具产生的输出示例

~ $ xargs
                a
                b
                c
                
                    Control-D
                
a b c
~ $

您可以发送通过 xargs 来输出文件名的任何工具的输出,以便为其他某些接受文件名作为参数的工具获得参数列表,如以下示例所示:
清单 15. xargs 工具的使用示例

~/tmp $ ls -1 | xargs
December_Report.pdf README a archive.tar mkdirhier.sh
~/tmp $ ls -1 | xargs file
December_Report.pdf: PDF document, version 1.3
README: ASCII text
a: directory
archive.tar: POSIX tar archive
mkdirhier.sh: Bourne shell script text executable
~/tmp $

xargs 命令不只用于传递文件名。您还可以在需要将文本筛选到单个行中的任何时候使用它:
清单 16. 好习惯 7 的示例:使用 xargs 工具来将文本筛选到单个行中

~/tmp $ ls -l | xargs
-rw-r--r-- 7 joe joe 12043 Jan 27 20:36 December_Report.pdf -rw-r--r-- 1 \
root root 238 Dec 03 08:19 README drwxr-xr-x 38 joe joe 354082 Nov 02 \
16:07 a -rw-r--r-- 3 joe joe 5096 Dec 14 14:26 archive.tar -rwxr-xr-x 1 \
joe joe 3239 Sep 30 12:40 mkdirhier.sh
~/tmp $

谨慎使用 xargs

从技术上讲,使用 xargs 很少遇到麻烦。缺省情况下,文件结束字符串是下划线 (_);如果将该字符作为单个输入参数来发送,则它之后的所有内容将被忽略。为了防止这种情况发生,可以使用 -e 标志,它在不带参数的情况下完全禁用结束字符串。


Back to top

了解何时 grep 应该执行计数——何时应该绕过

避免通过管道将 grep 发送到 wc -l 来对输出行数计数。grep-c 选项提供了对与特定模式匹配的行的计数,并且一般要比通过管道发送到 wc 更快,如以下示例所示:
清单 17. 好习惯 8 的示例:使用和不使用 grep 的行计数

~ $ time grep and tmp/a/longfile.txt | wc -l
2811

real    0m0.097s
user    0m0.006s
sys     0m0.032s
~ $ time grep -c and tmp/a/longfile.txt
2811

real    0m0.013s
user    0m0.006s
sys     0m0.005s
~ $

除了速度因素外,-c 选项还是执行计数的好方法。对于多个文件,带 -c 选项的 grep 返回每个文件的单独计数,每行一个计数,而针对 wc 的管道则提供所有文件的组合总计数。

然而,不管是否考虑速度,此示例都表明了另一个要避免地常见错误。这些计数方法仅提供包含匹配模式的行数——如果那就是您要查找的结果,这没什么问题。但是在行中具有某个特定模式的多个实例的情况下,这些方法无法为您提供实际匹配实例数量 的真实计数。归根结底,若要对实例计数,您还是要使用 wc 来计数。首先,使用 -o 选项(如果您的版本支持它的话)来运行 grep 命令。此选项 输出匹配的模式,每行一个模式,而不输出行本身。但是您不能将它与 -c 选项结合使用,因此要使用 wc -l 来对行计数,如以下示例所示:
清单 18. 好习惯 8 的示例:使用 grep 对模式实例计数

~ $ grep -o and tmp/a/longfile.txt | wc -l
3402
~ $

在此例中,调用 wc 要比第二次调用 grep 并插入一个虚拟模式(例如 grep -c)来对行进行匹配和计数稍快一点。


Back to top

匹配输出中的某些字段,而不只是对行进行匹配

当您只希望匹配输出行中特定字段 中的模式时,诸如 awk 等工具要优于 grep

下面经过简化的示例演示了如何仅列出 12 月修改过的文件。
清单 19. 坏习惯 9 的示例:使用 grep 来查找特定字段中的模式

~/tmp $ ls -l /tmp/a/b/c | grep Dec
-rw-r--r--  7 joe joe  12043 Jan 27 20:36 December_Report.pdf
-rw-r--r--  1 root root  238 Dec 03 08:19 README
-rw-r--r--  3 joe joe   5096 Dec 14 14:26 archive.tar
~/tmp $

在此示例中,grep 对行进行筛选,并输出其修改日期和名称中带 Dec 的所有文件。因此,诸如 December_Report.pdf 等文件是匹配的,即使它自从一月份以来还未修改过。这可能不是您希望的结果。为了匹配特定字段中的模式,最好使用 awk,其中的一个关系运算符对确切的字段进行匹配,如以下示例所示:
清单 20. 好习惯 9 的示例:使用 awk 来查找特定字段中的模式

~/tmp $ ls -l | awk '$6 == "Dec"'
-rw-r--r--  3 joe joe   5096 Dec 14 14:26 archive.tar
-rw-r--r--  1 root root  238 Dec 03 08:19 README
~/tmp $

有关如何使用 awk 的更多详细信息,请参见参考资料


Back to top

停止对 cat 使用管道

grep 的一个常见的基本用法错误是通过管道将 cat 的输出发送到 grep 以搜索单个文件的内容。这绝对是不必要的,纯粹是浪费时间,因为诸如 grep 这样的工具接受文件名作为参数。您根本不需要在这种情况下使用 cat,如以下示例所示:
清单 21. 好习惯和坏习惯 10 的示例:使用带和不带 cat 的 grep

~ $ time cat tmp/a/longfile.txt | grep and
2811

real    0m0.015s
user    0m0.003s
sys     0m0.013s
~ $ time grep and tmp/a/longfile.txt
2811

real    0m0.010s
user    0m0.006s
sys     0m0.004s
~ $

此错误存在于许多工具中。由于大多数工具都接受使用连字符 (-) 的标准输入作为一个参数,因此即使使用 cat 来分散 stdin 中的多个文件,参数也通常是无效的。仅当您使用带多个筛选选项之一的 cat 时,才真正有必要在管道前首先执行连接。


Back to top

结束语:养成好习惯

最好检查一下您的命令行习惯中的任何不良的使用模式。不良的使用模式会降低您的速度,并且通常会导致意外错误。本文介绍了 10 个新习惯,它们可以帮助您摆脱许多最常见的使用错误。养成这些好习惯是加强您的 UNIX 命令行技能的积极步骤。

Resources

Learn

Get products and technologies

  • 若要获得 mkdirhier 的副本,您可以从 Haskell compiler 下载某个版本。

Discuss

About the author

Michael Stutz 是 The Linux Cookbook 一书的作者,他仅使用开放源码软件对该书进行了设计和排版。他的研究兴趣包括数字出版和图书的发展未来。他使用各种 UNIX 操作系统已有 20 多年。您可以通过 stutz@dsl.org 与他联系。