linux shell中的管道执行

linux shell中管道发挥的作用是文件描述符重定向,例如 prog1 | prog2 | prog3,管道会将prog1的标准输出重定向为prog2的标准输入,将prog2的标准输出重定向为prog3的标准输入,prog1的标准输入和 prog3的标准输出并没有改变。比如命令"ps -ef | grep -w "nginx""将ps命令的标准输出内容作为grep的输入,两个命令的组合的只输出关于nginx进程的信息。

这里归档两个平时没有想明白的问题:

1、shell管道中程序按什么顺序执行?进程关系是什么样子?
当前有很多的shell程序,实现各不同,有的支持作业控制,代表有:bash(bourne again shell),有的不支持,代表有bourne shell。

prog1 | prog2 | prog3

1)在不支持作业控制shell中,prog3是shell的子进程,而prog1和prog2为prog3的子进程。执行如下图所示
(摘自APUE)
 2)对于支持作业控制的shell,prog1、prog2、prog3都为shell的子进程,在bash中的执行顺序为 prog1、prog2、prog3,具体和shell的实现有关。

[root@zhangst ~]# uname -a
Linux zhangst.F14 2.6.35.6-45.fc14.i686 #1 SMP Mon Oct 18 23:56:17 UTC 2010 i686 i686 i386 GNU/Linux
[root@zhangst ~]# ps -o pid,ppid,pgid,session,tpgid,tty,comm | cat | grep -v "*"
  PID  PPID  PGID  SESS  TPGID TT       COMMAND
 2667  2664  2667  2667  2689 pts/0    bash
 2689  2667  2689  2667  2689 pts/0    ps
 2690  2667  2689  2667  2689 pts/0    cat
 2691  2667  2689  2667  2689 pts/0    grep

上面的例子中ps、cat、grep三个进程都为bash的子进程,ps进程最先执行,并且三个进程在一个进程组中,ps为组长进程,这个组为前台进程组(TPGID),而bash为后台进程。


2、如何判断管道中程序是否成功执行?某个程序执行失败是否影响其它程序的执行?

1)shell中有一个变量数组PIPESTATUS,保存了上一个执行管道的状态。
echo ${PIPESTATUS[*]};就可以输出所有管道进程的执行状态。

[root@zhangst test]# ./0 | ./1 | ./2
[root@zhangst test]# echo ${PIPESTATUS[*]}
0 1 2 


0、1、2三个程序main函数中只包含一条return代码,分别返回 0,1,2。


2)bash中管道程序的执行相互不影响的,参考下面的例子:

[root@zhangst test]# ./0 | grep -v | ./2
用法: grep [选项]... PATTERN [FILE]...
试用‘grep --help’来获得更多信息。
2
0

[root@zhangst test]# echo ${PIPESTATUS[*]}
0 2 2 


0、2三个程序分别在标准错误输出输出0、2,然后返回0、2

grep -v是不正确的,不能正确执行,但是0和2都正确执行完毕了。

原文:http://blog.chinaunix.net/uid-21843265-id-3132119.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Linux ,多管道可以使用 pipe() 系统调用实现,具体实现步骤如下: 1. 创建多个管道 ```c int fd[2][2]; // fd[i][0] 代表第 i 个管道的读端,fd[i][1] 代表第 i 个管道的写端 for (int i = 0; i < n; i++) { if (pipe(fd[i]) == -1) { perror("pipe"); exit(EXIT_FAILURE); } } ``` 2. fork 出多个子进程,并将它们的标准输入、标准输出连接到管道 ```c int pid; for (int i = 0; i < n; i++) { pid = fork(); if (pid == -1) { perror("fork"); exit(EXIT_FAILURE); } else if (pid == 0) { // 子进程 if (i == 0) { // 第一个子进程 dup2(fd[i][1], STDOUT_FILENO); // 将标准输出连接到 fd[i][1] 上 close(fd[i][0]); // 关闭其它管道 for (int j = 1; j < n; j++) { close(fd[j][0]); close(fd[j][1]); } } else if (i == n - 1) { // 最后一个子进程 dup2(fd[i-1][0], STDIN_FILENO); // 将标准输入连接到 fd[i-1][0] 上 close(fd[i][0]); // 关闭其它管道 for (int j = 0; j < n - 1; j++) { close(fd[j][0]); close(fd[j][1]); } } else { // 间的子进程 dup2(fd[i-1][0], STDIN_FILENO); // 将标准输入连接到 fd[i-1][0] 上 dup2(fd[i][1], STDOUT_FILENO); // 将标准输出连接到 fd[i][1] 上 for (int j = 0; j < n; j++) { if (j != i - 1 && j != i) { close(fd[j][0]); close(fd[j][1]); } } } execlp(cmd[i][0], cmd[i], NULL); // 执行命令 perror("execlp"); // execlp 函数不返回,如果返回则说明出错了 exit(EXIT_FAILURE); } else { // 父进程 if (i == 0) { close(fd[i][1]); // 关闭写端 } else if (i == n - 1) { close(fd[i-1][0]); // 关闭读端 } else { close(fd[i-1][0]); close(fd[i][1]); } } } ``` 3. 等待子进程结束 ```c for (int i = 0; i < n; i++) { wait(NULL); } ``` 完整的代码实现如下: ```c #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <sys/wait.h> int main() { char *cmd[3][3] = { {"ls", "-al", NULL}, {"grep", "test", NULL}, {"wc", "-l", NULL} }; int n = 3; // 管道数量 int fd[2][2]; // fd[i][0] 代表第 i 个管道的读端,fd[i][1] 代表第 i 个管道的写端 for (int i = 0; i < n; i++) { if (pipe(fd[i]) == -1) { perror("pipe"); exit(EXIT_FAILURE); } } int pid; for (int i = 0; i < n; i++) { pid = fork(); if (pid == -1) { perror("fork"); exit(EXIT_FAILURE); } else if (pid == 0) { if (i == 0) { dup2(fd[i][1], STDOUT_FILENO); close(fd[i][0]); for (int j = 1; j < n; j++) { close(fd[j][0]); close(fd[j][1]); } } else if (i == n - 1) { dup2(fd[i-1][0], STDIN_FILENO); close(fd[i][0]); for (int j = 0; j < n - 1; j++) { close(fd[j][0]); close(fd[j][1]); } } else { dup2(fd[i-1][0], STDIN_FILENO); dup2(fd[i][1], STDOUT_FILENO); for (int j = 0; j < n; j++) { if (j != i - 1 && j != i) { close(fd[j][0]); close(fd[j][1]); } } } execlp(cmd[i][0], cmd[i], NULL); perror("execlp"); exit(EXIT_FAILURE); } else { if (i == 0) { close(fd[i][1]); } else if (i == n - 1) { close(fd[i-1][0]); } else { close(fd[i-1][0]); close(fd[i][1]); } } } for (int i = 0; i < n; i++) { wait(NULL); } return 0; } ```

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值