linux shell 管道命令(pipe)使用及shell重定向

管道命令操作符是:”|”,它仅能处理经由前面一个指令传出的正确输出信息,也就是 standard output 的信息,对于 stdandard 
error 信息没有直接处理能力。然后,传递给下一个命令,作为标准的输入 standard input.


  • 管道命令使用说明:

先看下下面图:

image

command1正确输出,作为command2的输入 然后comand2的输出作为,comand3的输入 ,comand3输出就会直接显示在屏幕上面了。

通过管道之后:comand1,comand2的正确输出不显示在屏幕上面

注意:

1、管道命令只处理前一个命令正确输出,不处理错误输出

2、管道命令右边命令,必须能够接收标准输入流命令才行。

实例:

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
[chengmo@centos5 shell]$ cat  test .sh | grep  -n 'echo'
5:    echo  "very good!" ;
7:    echo  "good!" ;
9:    echo  "pass!" ;
11:    echo  "no pass!" ;
#读出test.sh文件内容,通过管道转发给grep 作为输入内容
 
[chengmo@centos5 shell]$ cat  test .sh test1.sh | grep  -n 'echo'
cat : test1.sh: 没有那个文件或目录
5:    echo  "very good!" ;
7:    echo  "good!" ;
9:    echo  "pass!" ;
11:    echo  "no pass!" ;
#cat test1.sh不存在,错误输出打印到屏幕,正确输出通过管道发送给grep
 
 
[chengmo@centos5 shell]$ cat  test .sh test1.sh 2> /dev/null  | grep  -n 'echo' 
5:    echo  "very good!" ;
7:    echo  "good!" ;
9:    echo  "pass!" ;
11:    echo  "no pass!" ;
#将test1.sh 没有找到错误输出重定向输出给/dev/null 文件,正确输出通过管道发送给grep
 
 
[chengmo@centos5 shell]$ cat  test .sh | ls
catfile      httprequest.txt  secure  test             testfdread.sh  testpipe.sh    testsh.sh      testwhile2.sh
envcron.txt  python           sh      testcase.sh     testfor2.sh    testselect.sh  test .txt       text.txt
env .txt      release          sms     testcronenv.sh  testfor.sh     test .sh        testwhile1.sh
#读取test.sh内容,通过管道发送给ls命令,由于ls 不支持标准输入,因此数据被丢弃

 

这里实例就是对上面2点注意的验证。作用接收标准输入的命令才可以用作管道右边。否则传递过程中数据会抛弃。 常用来作为接收数据管道命令有:sed,awk,cut,head,top,less,more,wc,join,sort,split 等等,都是些文本处理命令。

  • 管道命令与重定向区别

区别是:

1、左边的命令应该有标准输出 | 右边的命令应该接受标准输入
   左边的命令应该有标准输出 > 右边只能是文件
   左边的命令应该需要标准输入 < 右边只能是文件

 

2、管道触发两个子进程执行"|"两边的程序;而重定向是在一个进程内执行

这些都是网上总结很多的,其实只要多加清楚用法,也一定有自己的一份不同描述。

实例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
#可以相互转换情况
#输入重定向
 
[chengmo@centos5 shell]$ cat  test .sh| grep  -n 'echo'
5:    echo  "very good!" ;
7:    echo  "good!" ;
9:    echo  "pass!" ;
11:    echo  "no pass!" ;
#"|"管道两边都必须是shell命令
 
 
[chengmo@centos5 shell]$ grep  -n 'echo'  < test .sh   
5:    echo  "very good!" ;
7:    echo  "good!" ;
9:    echo  "pass!" ;
11:    echo  "no pass!" ;
#"重定向"符号,右边只能是文件(普通文件,文件描述符,文件设备)
 
 
[chengmo@centos5 shell]$ mail -s 'test'  8292669@qq.com < test .sh
[chengmo@centos5 shell]$ cat  test .sh|mail -s 'test'  8292669@qq.com
#以上2个也相同,将test.sh内容发送到指定邮箱。
 
 
[chengmo@centos5 shell]$ ( sed  -n '1,$p' | grep  -n 'echo' )< test .sh
5:    echo  "very good!" ;
7:    echo  "good!" ;
9:    echo  "pass!" ;
11:    echo  "no pass!" ;
#这个脚本比较有意思了。由于前面是管道,后面需要把test.sh内容重定向到 sed ,然后sed输出通过管道,输入给grep.需要将前面用"()"
运算符括起来。 在单括号内的命令,可以把它们看作一个象一个命令样。如果不加括号test.sh就是grep 的输入了。
 
 
#上面一个等同于这个
[chengmo@centos5 shell]$ sed  -n '1,$p' < test .sh | grep  -n 'echo'
5:    echo  "very good!" ;
7:    echo  "good!" ;
9:    echo  "pass!" ;
11:    echo  "no pass!" ;
 
#重定向运算符,在shell命令解析前,首先检查的(一个命令,执行前一定检查好它的输入,输出,也就是0,1,2 设备是否准备好),所以优
先级会最高
 
 
[chengmo@centos5 shell]$ sed  -n '1,10p' < test .sh | grep  -n 'echo'  <testsh.sh
10: echo  $total;
18: echo  $total;
21:     echo  "ok" ;
#哈哈,这个grep又接受管道输入,又有testsh.sh输入,那是不是2个都接收呢。刚才说了"<"运算符会优先,管道还没有
发送数据前,grep绑 定了testsh.sh 输入,这样sed命令输出就被抛弃了。这里一定要小心使用
 
#输出重定向
 
[chengmo@centos5 shell]$ cat  test .sh> test .txt
[chengmo@centos5 shell] cat  test .sh| tee  test .txt &> /dev/null
#通过管道实现将结果存入文件,还需要借助命令tee,它会把管道过来标准输入写入文件test.txt ,然后将标准输入复制到标准输出(stdout),
所以重定向到 /dev/null 不显示输出 #">"输出重定向,往往在命令最右边,接收左边命令的,输出结果,重定向到指定文件。也可以用到命令
中间。
 
 
[chengmo@centos5 shell]$ ls  test .sh test1.sh testsh.sh 2>err.txt | grep  'test'
test .sh
testsh.sh
#目录下面有:test,testsh文件,test1.sh不存在,因此将ls 命令错误输出输入到err.txt 正确输出,还会通过管道发送
到grep命令。
[chengmo@centos5 shell]$ ls  test .sh test1.sh testsh.sh &>err.txt | grep  'test'
#这次打印结果是空,&代表正确与错误输出 都输入给err.txt,通过管道继续往下面传递数据为空,所以没有什么显示的
 
#同样">"输出重定向符,优先级也是先解析,当一个命令有这个字符,它就会与左边命令标准输出绑定。
准备好了这些,就等待 命令执行输出 数据, 它就开始接收

 

再概括下:

从上面例子可以看,重定向与管道在使用时候很多时候可以通用,其实,在shell里面,经常是【条条大路通罗马】的。一般如果是命令间传递参数,还是管道的好,如果处理输出结果需要重定向到文件,还是用重定向输出比较好。

命令执行顺序可以看下:Linux Shell 通配符、元字符、转义符使用实例介绍

 

  • shell脚本接收管道输入

有意思的问题:

既然作用管道接收命令,需要可以接收标准的输入,那么我们shell脚本是否可以开发出这样的基本程序呢?(大家经常看到的,都是一些系统的命令作为管道接收方)

实例(testpipe.sh):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
#!/bin/sh
  
  if  [ $ # -gt 0 ];then
      exec  0<$1;
#判断是否传入参数:文件名,如果传入,将该文件绑定到标准输入
  fi
  
  while  read  line
  do
      echo  $line;
  done <&0;
#通过标准输入循环读取内容
  exec  0&-;
#解除标准输入绑定

运行结果:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
[chengmo@centos5 shell]$ cat  testpipe.txt
1,t,est pipe
2,t,est pipe
3,t,est pipe
4,t,est pipe
#testpipe.txt 只是需要读取的测试文本
 
[chengmo@centos5 shell]$ cat  testpipe.txt | sh testpipe.sh
1,t,est pipe
2,t,est pipe
3,t,est pipe
4,t,est pipe
#通过cat 读取 testpipe.txt 发送给testpipe.sh 标准输入
 
[chengmo@centos5 shell]$ sh testpipe.sh testpipe.txt     
1,t,est pipe
2,t,est pipe
3,t,est pipe
4,t,est pipe
#testpipe.sh 通过出入文件名读取文件内容


1.文件描述符

在linux shell执行命令时,每个进程都和三个打开的文件相联系,并使用文件描述符来引用这些文件。由于文件描述符不容易记忆,shell同时也给出了相应的文件名:

文件文件描述符
输入文件—标准输入0(缺省是键盘,为0时是文件或者其他命令的输出)
输出文件—标准输出1(缺省是屏幕,为1时是文件)
错误输出文件—标准错误2(缺省是屏幕,为2时是文件)
系统中实际上有12个文件描述符,我们可以任意使用文件描述符3到9.


2.文件重定向:改变程序运行的输入来源和输出地点

2.1.输出重定向:

Command > filename把标准输出重定向到一个新文件中
Command >> filename把标准输出重定向到一个文件中(追加)
Command > filename把标准输出重定向到一个文件中
Command > filename 2>&1把标准输出和错误一起重定向到一个文件中
Command 2 > filename把标准错误重定向到一个文件中
Command 2 >> filename把标准输出重定向到一个文件中(追加)
Command >> filename2>&1把标准输出和错误一起重定向到一个文件(追加)

2.2.输入重定向:

Command < filename > filename2Command命令以filename文件作为标准输入,以filename2文件作为标准输出
Command < filenameCommand命令以filename文件作为标准输入
Command << delimiter 从标准输入中读入,知道遇到delimiter分界符

2.3.绑定重定向

Command >&m把标准输出重定向到文件描述符m中
Command < &-关闭标准输入
Command 0>&-同上


3.shell重定向的一些高级用法

3.1.重定向标准错误

例子1:
command 2> /dev/null
如果command执行出错,将错误的信息重定向到空设备
例子2:
command > out.put 2>&1
将command执行的标准输出和标准错误重定向到out.put(也就是说不管command执行正确还是错误,输出都打印到out.put)。


3.2.exec用法
exec命令可以用来替代当前shell;换句话说,并没有启动子shell,使用这一条命令时任何现有环境变量将会被清除,并重新启动一个shell(重新输入用户名和密码进入)。
exec command
其中,command通常是一个shell脚本。
对文件描述符操作的时候用(也只有再这时候),它不会覆盖你当前的shell


例子1:
#!/bin/bash
#file_desc


exec 3<&0 0<name.txt
read line1
read line2
exec 0<&3
echo $line1
echo $line2


其中:
首先,exec 3<&0 0<name.txt的意思是把标准输入重定向到文件描述符3(0表示标准输入),然后把文件name.txt内容重定向到文件描述符0,实际上就是把文件name.txt中的内容重定向到文件描述符3。然后通过exec打开文件描述符3;

然后,通过read命令读取name.txt的第一行内容line1,第二行内容line2,通过Exec 0<&3关闭文件描述符3;

最后,用echo命令输出line1和line2。最好在终端运行一下这个脚本,亲自尝试一下。


例子2:
exec 3<>test.sh;
#打开test.sh可读写操作,与文件描述符3绑定
 
while read line<&3
 do
    echo $line;
done
#循环读取文件描述符3(读取的是test.sh内容)
exec 3>&-
exec 3<&-
#关闭文件的,输入,输出绑定


  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
提供的源码资源涵盖了Java应用等多个领域,每个领域都包含了丰富的实例和项目。这些源码都是基于各自平台的最新技术和标准编写,确保了在对应环境下能够无缝运行。同时,源码配备了详细的注释和文档,帮助用户快速理解代码结构和实现逻辑。 适用人群: 适合毕业设计、课程设计作业。这些源码资源特别适合大学生群体。无论你是计算机相关专业的学生,还是对其他领域编程感兴趣的学生,这些资源都能为你提供宝贵的学习和实践机会。通过学习和运行这些源码,你可以掌握各平台开发的基础知识,提升编程能力和项目实战经验。 使用场景及目标: 在学习阶段,你可以利用这些源码资源进行课程实践、课外项目或毕业设计。通过分析和运行源码,你将深入了解各平台开发的技术细节和最佳实践,逐步培养起自己的项目开发和问题解决能力。此外,在求职或创业过程,具备跨平台开发能力的大学生将更具竞争力。 其他说明: 为了确保源码资源的可运行性和易用性,特别注意了以下几点:首先,每份源码都提供了详细的运行环境和依赖说明,确保用户能够轻松搭建起开发环境;其次,源码的注释和文档都非常完善,方便用户快速上手和理解代码;最后,我会定期更新这些源码资源,以适应各平台技术的最新发展和市场需求。 所有源码均经过严格测试,可以直接运行,可以放心下载使用。有任何使用问题欢迎随时与博主沟通,第一时间进行解答!
提供的源码资源涵盖了小程序应用等多个领域,每个领域都包含了丰富的实例和项目。这些源码都是基于各自平台的最新技术和标准编写,确保了在对应环境下能够无缝运行。同时,源码配备了详细的注释和文档,帮助用户快速理解代码结构和实现逻辑。 适用人群: 适合毕业设计、课程设计作业。这些源码资源特别适合大学生群体。无论你是计算机相关专业的学生,还是对其他领域编程感兴趣的学生,这些资源都能为你提供宝贵的学习和实践机会。通过学习和运行这些源码,你可以掌握各平台开发的基础知识,提升编程能力和项目实战经验。 使用场景及目标: 在学习阶段,你可以利用这些源码资源进行课程实践、课外项目或毕业设计。通过分析和运行源码,你将深入了解各平台开发的技术细节和最佳实践,逐步培养起自己的项目开发和问题解决能力。此外,在求职或创业过程,具备跨平台开发能力的大学生将更具竞争力。 其他说明: 为了确保源码资源的可运行性和易用性,特别注意了以下几点:首先,每份源码都提供了详细的运行环境和依赖说明,确保用户能够轻松搭建起开发环境;其次,源码的注释和文档都非常完善,方便用户快速上手和理解代码;最后,我会定期更新这些源码资源,以适应各平台技术的最新发展和市场需求。 所有源码均经过严格测试,可以直接运行,可以放心下载使用。有任何使用问题欢迎随时与博主沟通,第一时间进行解答!
提供的源码资源涵盖了Java应用等多个领域,每个领域都包含了丰富的实例和项目。这些源码都是基于各自平台的最新技术和标准编写,确保了在对应环境下能够无缝运行。同时,源码配备了详细的注释和文档,帮助用户快速理解代码结构和实现逻辑。 适用人群: 适合毕业设计、课程设计作业。这些源码资源特别适合大学生群体。无论你是计算机相关专业的学生,还是对其他领域编程感兴趣的学生,这些资源都能为你提供宝贵的学习和实践机会。通过学习和运行这些源码,你可以掌握各平台开发的基础知识,提升编程能力和项目实战经验。 使用场景及目标: 在学习阶段,你可以利用这些源码资源进行课程实践、课外项目或毕业设计。通过分析和运行源码,你将深入了解各平台开发的技术细节和最佳实践,逐步培养起自己的项目开发和问题解决能力。此外,在求职或创业过程,具备跨平台开发能力的大学生将更具竞争力。 其他说明: 为了确保源码资源的可运行性和易用性,特别注意了以下几点:首先,每份源码都提供了详细的运行环境和依赖说明,确保用户能够轻松搭建起开发环境;其次,源码的注释和文档都非常完善,方便用户快速上手和理解代码;最后,我会定期更新这些源码资源,以适应各平台技术的最新发展和市场需求。 所有源码均经过严格测试,可以直接运行,可以放心下载使用。有任何使用问题欢迎随时与博主沟通,第一时间进行解答!
Linux 使用 C 语言模拟 shell 命令可以通过调用系统函数实现。以下是一个简单的例子,演示了如何使用 C 语言实现重定向管道通信。 首先,我们需要包含一些头文件: ```c #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <fcntl.h> ``` 接下来,我们可以定义一些常量,例如: ```c #define MAX_ARGS 10 #define MAX_BUFFER 1024 ``` 然后,我们可以定义一个函数来解析用户输入命令,并将其分解为单个参数。以下是一个简单的实现: ```c void parse_command(char *command, char **args, int *redirect_input, int *redirect_output) { int arg_count = 0; char *token; char *rest = command; while ((token = strtok_r(rest, " ", &rest))) { if (*token == '<') { *redirect_input = open(token + 1, O_RDONLY); } else if (*token == '>') { *redirect_output = open(token + 1, O_WRONLY | O_CREAT | O_TRUNC, 0644); } else { args[arg_count++] = token; } } args[arg_count] = NULL; } ``` 此函数通过使用 `strtok_r()` 函数将命令分解为参数。如果命令包含输入重定向符 `<`,则将 `redirect_input` 指针设置为打开输入文件的文件描述符。如果命令包含输出重定向符 `>`,则将 `redirect_output` 指针设置为打开输出文件的文件描述符。在解析完成后,参数将存储在 `args` 数组。 接下来,我们可以定义一个函数来处理管道通信。以下是一个简单的实现: ```c void pipe_commands(char **commands) { int fd[2]; pid_t pid1, pid2; char *args1[MAX_ARGS], *args2[MAX_ARGS]; if (pipe(fd) == -1) { perror("pipe"); exit(EXIT_FAILURE); } parse_command(commands[0], args1, NULL, &fd[1]); parse_command(commands[1], args2, &fd[0], NULL); pid1 = fork(); if (pid1 == -1) { perror("fork"); exit(EXIT_FAILURE); } else if (pid1 == 0) { close(fd[0]); dup2(fd[1], STDOUT_FILENO); close(fd[1]); execvp(args1[0], args1); } else { pid2 = fork(); if (pid2 == -1) { perror("fork"); exit(EXIT_FAILURE); } else if (pid2 == 0) { close(fd[1]); dup2(fd[0], STDIN_FILENO); close(fd[0]); execvp(args2[0], args2); } else { close(fd[0]); close(fd[1]); wait(NULL); wait(NULL); } } } ``` 此函数创建一个管道,然后使用 `parse_command()` 函数解析两个命令,并将其分别存储在 `args1` 和 `args2` 数组。接下来,它调用 `fork()` 函数创建两个子进程,其一个子进程执行第一个命令,另一个子进程执行第二个命令使用 `dup2()` 函数将子进程的标准输出或标准输入连接到管道的适当端口。最后,主进程等待两个子进程完成。 最后,我们可以定义一个主函数来使用这些函数来执行用户输入命令。以下是一个简单的实现: ```c int main() { char buffer[MAX_BUFFER]; char *commands[2]; int redirect_input = 0, redirect_output = 0; while (1) { printf("$ "); if (fgets(buffer, MAX_BUFFER, stdin) == NULL) break; commands[0] = strtok(buffer, "|"); if ((commands[1] = strtok(NULL, "\n")) != NULL) { pipe_commands(commands); } else { parse_command(commands[0], commands, &redirect_input, &redirect_output); pid_t pid = fork(); if (pid == -1) { perror("fork"); exit(EXIT_FAILURE); } else if (pid == 0) { if (redirect_input) { dup2(redirect_input, STDIN_FILENO); close(redirect_input); } if (redirect_output) { dup2(redirect_output, STDOUT_FILENO); close(redirect_output); } execvp(commands[0], commands); } else { wait(NULL); } } } return 0; } ``` 此函数使用 `fgets()` 函数从标准输入读取用户输入命令。如果命令包含管道符 `|`,则使用 `strtok()` 函数将命令分解为两个命令,并使用 `pipe_commands()` 函数执行它们之间的管道通信。否则,就使用 `parse_command()` 函数解析命令,并使用 `fork()` 函数创建子进程来执行命令。在子进程使用 `dup2()` 函数将标准输入或标准输出重定向到适当的文件描述符。最后,主进程使用 `wait()` 函数等待子进程完成。 这就是使用 C 语言模拟 shell 命令的基本方法。请注意,此实现仅用于演示目的,并且可能需要进行更改以处理更多情况。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值