Skip to content

Latest commit

 

History

History
144 lines (83 loc) · 7.94 KB

0X09_文件流.md

File metadata and controls

144 lines (83 loc) · 7.94 KB

0X09 文件流

文件编辑

类Unix系统的哲学是'一切都是文件'.而一切文件归根结底都是二进制文件.但是作为系统管理员来说,我们不需要去读懂二进制文件,也不需要用Photoshop进行花哨的图形处理.只要能处理纯文本文件(plain text)就可以了.

从另一个角度说,由于二进制文件,字节流,纯文本文件之间的对应关系.我们可以用处理纯文本的套路处理任何文件(高效不高效另说).所以,掌握纯文本文件的处理就掌握了最最基本的文件处理方法.

文本编辑器

要编辑本文文件,自然就需要一个编辑器.在Windows下最基本的编辑器应该就是记事本.而在Linux系统中的终端界面下,常用的文本编辑器有三种:vi/vim,emacs,nano.三者各有所长,但是如果你想找一个使用体验最接近记事本,也比较简单的编辑器.我推荐你用nano.(我本人其实用emacs多一点.emacs读音/ˈiːmæks/.)

这些编辑器的内容我就不在这个教程里展开了.你可以去网上搜到很多教程.随便掌握一款就足够了(会打字,会保存,会退出就行).我在<<太玄的工具库>>系列中介绍过vim的基本用法.以后也可能会出emacs教程.感兴趣的可以去看一下.

如果不需要修改文件,仅仅是查看文件内容,你就可以使用less命令.例如:

less /proc/meminfo

进入less的界面后,使用方向键进行移动.按q键退出.

文件流

从前往后,逐个字节读取,处理或者输出一个字节串的方式,就是我们所说的'流'.

所有的文件归根结底,都可以用二进制字节流表示.所以所有文件都可以用这种方式处理.即从强往后逐个字节处理.我们一般也把正在流式处理中的文件称为'文件流'.对一个程序而言,根据流式处理的文件的读写模式不同,可以分为'输入流'和'输出流'.这里的输入流输出流,其实就对应我在Lua教程中介绍过的io中的函数.

echo命令本质是把参数输出到它的输出流.默认的输出流对应终端.所以会把结果显示到终端上.ls等命令也类似.(Coreutils中像echo这样只用于向输出流输出的命令还有yes和printf.)

标准输入输出流

Linux中有几个特殊文件,实际上是设备的映射.向它们进行读写实际上就是在操作设备.一般来说有一组基本的流会映射到终端的显示和键盘输入上,并且流式读写,称为'标准输入输出流'.

Linux有3个表内准输入输出文件,分别用0、1、2三个文件描述符表示。0表示STDIN,标准输入;1表示STDOUT,标准输出;2表示STDERR,标准错误输出。标准错误输出也是一个输出流,只不过专门用来输出错误信息,这样可以防止业务数据和调试数据混在一起。

重定向

对于使用了输入输出流的程序,我们可以通过重定向,来改变其读写数据的位置。

ls > lsRecord 把ls的结果保存成文件lsRecord,而不是输出到显示器上。有意思的是这个文件本身也名列其中。显然是先创建了文件,然后运行ls并把输入流导入。

echo 'Goodbye World.' >> lsRecord 用一个大于号,则每次输出到文件都会覆盖原有内容。而使用两个大于号表示在文件结尾追加内容。

less < lsRecord less命令也可以这样用。这是把文件lsRecord作为less命令的输入流。

可以同时重定向输入流和输出流。例子中的grep是文本过滤工具。参数“zip”,表示从输入流中筛选带“zip”的项目并输出到输出流。第二条命令就表示grep从binls文件读取,找出带“zip”的项目,然后输出到grepResult文件。

ls /bin > binls
grep zip < binls >grepResult

默认的输出重定向只重定向标准输出。如果要指定错误输出重定向,则使用2>。如果同时重定向两个输出流,则标准输出使用1>。如果要指明标准输入重定向可以用0<。例如ls /bin /dev /windows 2> errors 1> lsResult

(注意,交互式shell的命令提示符走标准错误输出.要把提示符也重定向,需要重定向标准错误.)

可以把标准输出重定向到标准错误输出,反之亦然。echo是向标准输出流输出。如果需要在脚本输出到标准错误流,则使用>&2把标准输出流的内容用标准错误输出流输出。反之则用>&1。(这里问文件述符前面加&的原因和变量前加$类似。)

ls /windows 1>lsout 2>&1中是把表准输出重定向到lsout文件,然后把标准错误输出重定向到标准输出。标准错误输出经由标准输出输出到lsout。注意顺序乱了结果就会不一样。一般用法是要输出到标准输出就不重定向,需要输出到标准错误输出再跟上>&2临时重定向到标准错误输出。

在脚本中如果要永久改变重定向(直到脚本结束或者下一条永久重定向命令),就使用exec。

  • exec 0< myFile 此命令以后标准输入重定向到myFile。
  • exec 1> outFile 此命令后标准出重定向到outFile。
  • exec 2> err 此命令后标准错误输出重定向到err。

自定义输入输出流

标准输入输出只用了3个数字作为文件描述符。剩余的7个数字符号都可以作为输入输出流文件描述符,只不过需要先定向后再使用。

示例:

exec 3>myFile3
echo >&3t

输入也可以重定向

exec 4<myFile3
less 0<&4

关闭流。例如关闭3号流:exec 3>&-

特殊文件

如果你不希望输出流输出到屏幕或任何文件中,就把它重定向到/dev/null。任何定向到这里的数据都会被丢弃。一种常见的用法是屏蔽错误信息exec 2> /dev/null

如果把/dev/null作为输入流定向给交互式shell,shell会退出。

一般临时文件会创建于/tmp目录。任何用户都有权限在其中读写。但是这个目录中的内容会定期清理。

使用命令mktemp可以在/tmp文件自动创建临时文件(或者临时目录)并返回文件路径.

注意,大多数Linux发行版会在启动的时候清空/tmp目录.

管道

使用符号|链接命令,会将前一个命令的输出作为后一个命令的输入。这种功能称为管道。例如ls /bin | less

可以多个命令连用ls /bin | grep zip | less

流式编辑器

以输入流为输出,把处理结果输出到输出流中的编辑器称为流式编辑器.如果要执行一系列的编辑操作,就可以用管道连接多个流式编辑命令.这样整个处理过程就会像流水线一样.

常见的此类工具包括grep,sed和awk.

如果不做专门的系统管理员,sed和awk其实没有必要学习.但是多少学一点grep会让你的生活更加美好.

关于流式编辑器的内容,我建议参看这个教程:

除了grep,sed和awk这流式编辑三大件.Coreutils中还提供了一些用于流式处理的小工具.

例如之前介绍过的cat的作用就是把一个文件的内容输出到标准输出流.实验:

cat /proc/meminfo
cat /proc/meminfo | grep Mem

此外还有tee, tac, nl, od, base32, base64, fmt, pr, fold, head, tail, sort, shuf, comm, tsort, cut, paste, join, tr, expand, unexpand等.

正则表达式

使用流式编辑就绕不开正则表达式.我在Lua教程中介绍了Lua中正则表达式的用法.在bash和流式编辑器中,正则表达式的写法和Lua中略有不同但是大同小异.例如这个命令显示所有/bin目录下以'sys'开头的项目:

ls /bin | grep '^sys'

另外,rm,trash之类的文件操作命令也是可以用正则表达式的.比如删除当前路径下所有以'~'结尾的文件.

trash *\~

在文件操作的时候,使用正则表达式可以轻松处理大量文件。bash中所支持的各种正则表达式用法,详见bash的手册。