自带的文件管理系统是 IDE 亮点功能之一,从最基本的文件移动、重命名和删除功能,到更加具体的编译和句法检查。批量文件的操作也非常有用,比如找出某种后缀或大小的所有文件,或者搜索出有一定命名模式的文件。在本系列的第一篇文章里,我将考察一些非常有用的工具来对批量文件进行操作,这些工具应该也是大多数 Linux 用户所熟知的。
ls
恐怕是某管理员最初学的用以显示某路径下的文件列表的命令之一,而大多数管理员也应该是知道 -a
和 -l
选项,它们分别是用来显示包括点文件(即隐藏文件)在内的所有文件和更详细的文件相关的信息栏。
还有一些 ls
的选项不那么常用,但是对编程很有帮助:
-t
—— 按最后编辑日期排序,最新的最先。这在某个大目录里找出最近修改的文件列表时很有用,比如将结果导入(pipe
)head
或者sed 10q
。或许加上-l
会效果更好。当然如果你想获取最旧的文件列表,只要加-r
反转列表即可。-X
—— 按文件类型分类。这在多语言或多后缀的项目中特别方便,比如头文件和源文件分开,或区分开源文件和生成文件或目录。-v
—— 按照文件名里的版本号排序。-S
—— 按文件大小排序。-R
—— 递归地列举文件。这个选项和-l
组合使用并将结果导出到less
效果很好。
因为生成的列表就是文本,所以你其实可以把结果导出给类似 vim
的进程,然后再加上一些对每个文件作用的解释,这就成了一个目录文件,又或者把列表加进 README 文件:
$ ls -XR | vim -
这种工作其实我们可以很容易地让 make
自动生成,我会在之后的文章里谈到。
非常有趣的是你其实可以只用一个 find
命令,不用任何其他参数就列出所有文件,甚至还包括相对路径。当然如果把结果导入 sort
肯定效果更好:
$ find | sort . ./Makefile ./README ./build ./client.c ./client.h ./common.h ./project.c ./server.c ./server.h ./tests ./tests/suite1.pl ./tests/suite2.pl ./tests/suite3.pl ./tests/suite4.pl
如果你想要 ls -l
样式的列表,只要在 find
后面加上 -ls
:
$ find -ls | sort -k 11 1155096 4 drwxr-xr-x 4 tom tom 4096 Feb 10 09:37 . 1155152 4 drwxr-xr-x 2 tom tom 4096 Feb 10 09:17 ./build 1155155 4 -rw-r--r-- 1 tom tom 2290 Jan 11 07:21 ./client.c 1155157 4 -rw-r--r-- 1 tom tom 1871 Jan 11 16:41 ./client.h 1155159 32 -rw-r--r-- 1 tom tom 30390 Jan 10 15:29 ./common.h 1155153 24 -rw-r--r-- 1 tom tom 21170 Jan 11 05:43 ./Makefile 1155154 16 -rw-r--r-- 1 tom tom 13966 Jan 14 07:39 ./project.c 1155080 28 -rw-r--r-- 1 tom tom 25840 Jan 15 22:28 ./README 1155156 32 -rw-r--r-- 1 tom tom 31124 Jan 11 02:34 ./server.c 1155158 4 -rw-r--r-- 1 tom tom 3599 Jan 16 05:27 ./server.h 1155160 4 drwxr-xr-x 2 tom tom 4096 Feb 10 09:29 ./tests 1155161 4 -rw-r--r-- 1 tom tom 288 Jan 13 03:04 ./tests/suite1.pl 1155162 4 -rw-r--r-- 1 tom tom 1792 Jan 13 10:06 ./tests/suite2.pl 1155163 4 -rw-r--r-- 1 tom tom 112 Jan 9 23:42 ./tests/suite3.pl 1155164 4 -rw-r--r-- 1 tom tom 144 Jan 15 02:10 ./tests/suite4.pl
要注意,在这种情况下,我得设定 sort
对第11列排序,即对文件名排序;这里所用的标签是 -k
。
find
有它自己的一套复杂的过滤语句。下面列举的是一些最常用的你可以用以获取某些文件列表的过滤器:
find -name '*.c'
—— 查找符合某 shell 式样式的文件名的文件。用iname
开启大小写不敏感搜索。find -path '*test*'
—— 查找符合某 shell 式样式的路径的文件。用ipath
开启大小写不敏感搜索。find -mtime -5
—— 查找近五天内编辑过的文件。你也可以用+5
来查找五天之前编辑过的文件。find -newer server.c
—— 查找比server.c
更新的文件。file -type d
—— 查找所有文件夹。如果想找出所有文件,那就用-type f
;找符号连接就用-type l
。
要注意,上面提到的这些过滤器都是可以组合使用的,例如找出近两天内编辑过的 C 源码:
$ find -name '*.c' -mtime -2
默认情况下, find
对搜索结果所采取的动作只是简单地通过标准输出输出一个列表,然而其实还有其他一些有用的后续动作:
-ls
—— 如前文,提供了一种类ls -l
式的列表。-delete
—— 删除符合查找条件的文件。-exec
—— 对搜索结果里的每个文件都运行某个命令,{}
会被替换成适当的文件名,并且命令用\;
终结。例如:$ find -name '*.pl' -exec perl -c {} \;
你也可以使用
+
作为终止符来对所有结果运行一次命令。我还发现一个我经常使用的小技巧,就是用find
生成一个文件列表,然后在 Vim 的垂直分窗中编辑:$ find -name '*.c' -exec vim {} +
早先版本的 Unix as IDE 建议 xargs
与 find
配合使用。在大多数情况下并不需要这么做,而且使用 -exec
或是 while read -r
循环的方式来处理文件名中带空格的文件更加灵活。
更多时候,我们对基于文件内容的搜索比基于文件属性的搜索更感兴趣。这毫无疑问用 grep
,更加具体来说,应该是 grep -R
。它会递归地找出当前目录下符合‘someVar’的文件:
$ grep -FR 'someVar' .
別忘了大小不敏感的标签,因为 grep
默认工作方式是大小写敏感的:
$ grep -iR 'somevar' .
而且,你也可以用 grep -l
光打印出符合条件的文件名而非文件内容选段。
$ grep -lR 'somevar' .
如果你写的脚本或批处理任务需要上面的输出内容,可以使用 while
和 read
来处理文件名中的空格和其他特殊字符:
grep -lR someVar | while IFS= read -r file; do head "$file" done
如果你在你的项目里使用了版本控制软件,它通常会在 .svn
, .git
, .hg
目录下包含一些元数据。你也可以很容易地用 grep -v
把这些目录移出搜索范围,当然得用 grep -F
指定一个恰当且确定的字符串,即要移除的目录名:
$ grep -R 'someVar' . | grep -vF '.svn'
部分版本的 grep
包含了 --exclude
和 --exclude-dir
选项,这看起来更加易读。
当然,还有另外一种很流行的 代替 grep 的工具叫做 ack
,默认情况下它就帮你把上面那些个麻烦的东西免除了。它同样也支持大多数黑客最爱的 Perl 兼容的正则表达式(PCRE)。而且它还有很多实用功能来帮助你完成有关源代码的工作。当然使用古朴的 grep
没什么不好的,无论怎样它是 Unix 系统自带的,但是如果你可以安装 ack
,我还是非常推荐的。现在你已经可以很容易地用个叫 ack-grep
Debian 包或者一个 Perl 脚本来安装。
我提到用一些较新的 Perl 脚本来代替经典工具 grep
可能会让一些 Unix 纯粹主义者很不爽。但是我不认为 Unix 哲学或以 Unix 作 IDE ,就是非要在有一些可用来解决新问题的工具时反而使用一些“古典”工具,毕竟这些新工具跟那些“古典”工具在思想上是一致的。
file
工具可以对所给的文件一行简短的介绍,它用文件后缀、头部信息和一些其他的线索来判断文件。你在检查一堆你不熟悉的文件时使用 find
非常方便:
$ find -exec file {} \; .: directory ./hanoi: Perl script, ASCII text executable ./.hanoi.swp: Vim swap file, version 7.3 ./factorial: Perl script, ASCII text executable ./bits.c: C source, ASCII text ./bits: ELF 32-bit LSB executable, Intel 80386, version ...
作为本篇文章的最后一个技巧,我会建议你学习一些有关模式匹配和 Bash 下的括号表达式。你可以在我之前的一篇叫做 Bash shell expansion 的文章里看到。
以上便把经典 Unix 命令行变成了一个可在编程项目中使用的非常强大的文件管理器。