以前一直觉得pipe是个非常简单的东西,简单到不必刻意花哪怕是一分钟时间去研究,今天遇到一个问题就栽在pipe上。
问题背景大概如下:
在安装oracle 11.2 的grid infra的时候,有一步需要运行一个脚本。可是这个脚本总是出错。 后来在网上查,解决办法如下,
/bin/dd if=/var/tmp/.oracle/npohasd of=/dev/nullbs=1024 count=1
这个方法确实好用,可是想来想去百思不得其解。 这段命令就是把一个文件的内容读出来,然后扔掉,nothing else,为什么这样就能保证执行成功呢?简单check了一下,发现这个input file是个pipe 文件。 于是去查了一下pipe文件的一些知识,总结如下。
pipe有两种,一种是没有名字的,也就是经常用的 ls -l | grep 之类。 另一种就是有名字的,比如下面的命令就创建了一个有名字的pipe
mkfifo pipe1
没错,创建有名字的pipe就是用mkfifo。pipe嘛,就像一个队列一样,先进先出,自然是fifo。
有名字的pipe也是pipe,它存在的意义跟普通的pipe(也就是我们常用的没有名字的pipe | )是一样的,一个进程向其中写内容,另外一个或多个进程从其中读内容。要注意的是,有下面几点。
1. 写的内容被读了以后就没有了
2. 写的进程,如果没有其他进程去读取pipe的内容,写的进程就会被block
3. 读的进程可以先打开pipe 等待写的进程去写
我们一一验证一下,
mkfifo pipe1
写一个脚本a.sh 如下
i=1;
while [ $i -lt 4800 ]
do
i=$[ $i + 1 ]
echo $i
done
然后开两个session
都输入cat pipe1
这时在原来的session 输入下面的命令
./a.sh >pipe,也就是把 a.sh 的输出重定向到pipe中去
这时你会发现在另外两个session中都读出了数据,但是数据都不完整,这是因为他们在争抢pipe中的数据,有人挣到1 有让挣到了2.
ok,那么这个小实验就验证了1 和 3.
至于第二条相当好验证了,你去输入 ls > pipe 这时就会卡在那里。 如果从其他session cat pipe,这样就能让ls >pipe完成。
其实这就可以解释前面grid的问题, 那条命令所做的就是把一个pipe读了一下,可想而知,肯定是之前有个进程在写pipe,但是没人读,所以卡住了。
但是为什么会有人写呢? 为什么写了一些没人读的内容呢? 猜想可能是登陆信息。