【深入浅出Linux】Linux管道命令踩坑实录
前言
看这个问题前我们要先明白什么是管道。
管道是一种通信机制,通常用于进程间的通信(也可通过socket进行网络通信),它表现出来的形式将前面每一个进程的输出(stdout)直接作为下一个进程的输入(stdin)。
管道命令使用|
作为界定符号,管道命令与上面说的连续执行命令不一样。
-
管道命令仅能处理standard output,对于standard error output会予以忽略。
less,more,head,tail...都是可以接受standard input的命令,所以他们是管道命令
ls,cp,mv并不会接受standard input的命令,所以他们就不是管道命令了。 -
管道命令必须要能够接受来自前一个命令的数据成为standard input继续处理才行。
$ ls -al /etc | less
通过管道将ls -al
的输出作为 下一个命令less
的输入,方便浏览。
正题
接下来进入正题
我想输出xxx.log的每一行,并且在最后输出num:行数。
看看下面的脚本能帮我们做到吗?
#!/bin/bash
#while循环
num=0
cat xxx.log | while read line ;do
echo $line
((num++))
done
echo num:$num
上面的脚本却并不能帮我们做到这一点,为什么?
因为用到了管道的命令,管道两边的命令的执行是依托于开辟进程的方式执行的,因此执行cat xxx.log | while read line ...
时,会在当前bash的基础上,开辟两个进程执行上面的两个命令。
上述的过程就是一个fork的概念,什么叫fork?
fork就是复制一个与当前进程一样的进程。新进程的所有数据(变量、环境变量、程序计数器等)数值都和原进程一致,但是是一个全新的进程,并作为原进程的子进程。
这里要明白几点:
- fork对进程所有的地址空间全部进行了复制。
- linux中进程中的指针地址是偏移量. 不是绝对地址
- 各种进程当中的偏移量相同, 指向不同地址.
- 要共享数据, 必须通过操作系统的进程间通信方法, 共享内存.
因而,对于一个变量来说,fork后父子进程各持有一个指针,这个指针在上述例子中指向num内存地址。而在linux中,如果一个进程试图去修改变量时,系统就会把这个变量拷贝一份单独给这个进程,而这个修改操作并不会影响到其他进程中变量的值。而这个原理其实就是Linux的写时复制原理。
所以我们在命令中修改的是该子进程对应 num的值,因此对应父进程的num变量无影响。
下一篇博客我会,深度总结一下Linux的写时复制的原理☺
???