重学操作系统(六)
前言
通过上一篇文章,帮助我巩固了Linux一些简单的命令的使用和原理。接下来,后面这个文章,介绍些和进程,重定向,以及管道指令相关的事情。
贯穿全文的问题:xargs指令的作用是什么?
进程
应用的可执行文件是在文件系统中,当执行的时候,会在操作系统中(内存)形成一个应用副本,这个副本就是进程。
什么是进程?
定义:进程是应用的副本
作用:进程是操作系统分配资源的最小单位
ps
查看当前进程,p代表processes(进程),s代表snapshot(快照)。
TTY:过去用来传递信息,现在可以指代传真,邮件,微信等。
操作系统上的TTY是一个输入输出终端的概念,比如用户打开一个bash,操作系统就为用户分配一个输入输出终端。没有加任何参数的ps只显示在同一个TTY的进程。
ps -e:用来显示所有进程,-e没有特殊含义,只为了和-A区分开。通常用ps -ef比较多,-f的作用是显示更多描述信息。

ps -e 输出结果 
ps -ef 输出结果 从上面两个图片可以看出,ps-ef显示更多的信息,包括(从左到右):
- UID:进程所有者
- PID:进程唯一标识
- PPID:进程的父进程ID
- C:CPU利用率(CPU占用)
- STIME:开始时间
- TTY:进程所在TTY,如果没有,是?
- TIME
- CMD:进程启动时命令,如果不是Shell命令,用方括号括起来,那就是系统进程或者内核进程
ps aux:功能类似ps -e,但是是BSD(加州伯克利分校)研发的UNIX分支版本的衍生风格,如下:

ps aux 输出结果
top
top能力和ps差不多,但是显示的不是快照,而是实时更新数据。

管道(Pipeline)
管道的作用,是在命令和命令之间,传递数据。比如一个命令的结果,可以作为另一个命令的输入。这里的命令就是进程,因此管道可以说,是在进程间传递数据。
输入输出流
每个进程都有自己的标准输入流,标准输出流和标准错误流。根本上来说,这几个标准流都是文件。
- 标准输入流(用0表示):可以作为进程执行的上下文
- 标准输出流(用1表示):写入的结果会被打印到屏幕上
- 标准错误流(用2表示):如果在进程执行过程中,发生异常,那么异常信息就会被记录到标准错误流中
重定向
重定向符号的作用是,将标准输出流输出的结果,重定向到一个文件中。
‘>’符号:覆盖重定向
‘>>’符号:追加重定向
比如:ls -l > out,将ls -l的输出,写入out文件,如果out文件是有内容,则覆盖。
start.sh >> logfile,将运行日志追加进logfile中
ls1 > out,这个结果不会存入out,因为ls1指令不存在
ls1 &> out,写法等价于,ls1 >out 2 &>1,重定向标准错误流
&代表引用关系,在上述中代表了ls1 > out的标准输出流
管道的作用和分类
管道和重定向很像,但是管道是一个连接一个计算,重定向是将一个文件的内容,定向到另以恶搞文件。
Linux中,管道也是文件,其中有两种类型:
- 匿名管道(Unnamed Pipline),这种管道也在文件系统中,它只是一个存储节点,不属于任何目录(没有路径)
- 命名管道(Named Pipline),这种管道就是一个文件,有自己的路径
FIFO
管道具有FIFO的特性,所以先进入管道的数据,先传递到管道的下游。
使用场景
Linux提供了’|’作为管道符,’|’左面的输出结果会作为右面的输入结果。
排序
比如使用ls,希望按照文件名排序倒序,可以使用匿名管道,将ls的结果传给sort指令。
ls | sort -r (-r是reverse)
去重
去重可以使用uniq指令,uniq指令查找文件中相邻的重复行,然后去重,但是如果重复行是交替的,就不能直接uniq,可以先sort然后利用管道,将sort结果重定向到uniq指令。
sort text.txt | uniq
筛选
筛选可以利用grep结合管道,比如
find ./ | grep Spring 查找当前路径下所有包含Spring关键字
(Tips: find的作用是在所指定路径中递归查找文件)
grep -v xxx 查找不包含xxx的结果
计算行数
- 如果想知道一个文件中有多少行,可以用wc -l 文件名
- 如果想知道目录下有多少文件,用ls | wc -l
- 如果计算一个java项目的目录中,有多少行代码,可以用:find -i ‘.java’ ./ | wc -l
中间结果
如果多个管道相连,我们想保存下中间的结果,就需要用到tee指令。tee指令从标准输入流中读取数据到标准输出流。tee的另一个作用是,在这个过程中,把输入流的数据存到文件中,比如:
find ./ -i "*.java" | tee JavaList | grep Spring
这个指令的意思是,在当前目录找到所有Spring关键字的Java文件,tee本身不影响指令的执行,但是tee会把find的结果存到JavaList文件中。
tee就像T,连接通道两端,下面开了个口,这个开口在函数式编程,叫副作用。
xargs
xargs指令,从标准数据流中构造并执行一行行的指令。xargs从输入流获取字符串,利用空白,换行符等切割字符,在这些字符串的基础上,构造指令,最后一行行的执行这些指令。
比如要重命名x.a,y.a,z.a三个文件,想在它们前面都加上prefix_前缀,就可以用xargs。假设它们三个在一个文件夹中,并且文件夹中没有其它文件,可以直接用指令:ls | xargs -I FILE mv FILE prefix_FILE
这里,FILE是指代ls查找的所有文件名,-I是查找替换符。
样板代码:如果上述例子,不用xargs,那么我们需要自己敲代码完成文件的重命名:
mv x.a prefix_x.a
mv y.a prefix_y.a
mv z.a prefix_z.a
这就是样板代码
管道文件
命名管道文件是要在文件夹中,有自己的路径,因此需要创建。可以使用mkfifo指令创建命名管道,比如mkfifo pipe1。明明管道和匿名管道能力类似。
比如我们创建一个命名管道叫pip,如果这时候用cat pip,则不打印任何东西。
Tips: cat指令的作用是,将文件内容打印到屏幕
之后如果执行 echo ‘abc’ > pip,将abc写入pip,屏幕中会打印abc
Tips: 可以使用cat pip &指令,&的意思是后台执行,这样就不会阻塞用户继续输入。
总结
这一篇文章的内容,对于我来说,是全新的,帮助我加深了对Linux命令的了解,也更加清晰,一些常见命令,比如grep,cat等和其它命令通过’|’连接,具体是如何执行的,并且原理是什么。目前这个主题的文章看到这,我已经惊叹不已,基本把我对计算机原理,Linux基础命令的漏洞,都补充上了。