当前位置: 首页 > Linux

SHELL(bash)脚本编程之三:重定向

时间:2023-04-06 06:07:43 Linux

在这篇文章中,我们介绍了输入输出重定向和管道的一些基础知识,本文将继续重定向的话题。在我们开始之前,让我们谈谈shell中的引用。Quote和很多编程语言一样,bash也支持字符转义,用来改变字符的原意,使一些元字符(如&)可以出现在命令中。bash中的引号分为三种,彼此略有不同:第一种是反斜杠(\),它转义紧跟在它后面的字符[root@centos7temp]#echo\$PATH$PATH[root@centos7temp]#第二个是单引号(''),它禁止解析包含的文本。第三个是双引号(“”),它防止部分解析,但允许一些单词扩展。在双引号中仍然保持特殊含义的字符包括:$`\!#其中$(展开:变量展开、数学展开、命令替换)和`(命令替换)保持其特殊含义;#双引号中的反斜杠\这一行只有在后面跟着如下字符时才保持其特殊意义:$`"\!;#默认情况下,感叹号!(历史展开,下篇说明)仅在交互式shell中使用,脚本中不能进行History和expansion#第一篇文章中提到,当@和*用于双引号内的位置变量和数组变量时,含义不同:#"$@"and"${array[@]}"展开后,每个元素都是一个单独的词inbash:$'string'.stringstring被反转斜线转义的字符有特殊含义,遵循ANSIC标准,部分解释见示例:[root@centos7~]#echo$'\u4f60\u597d\uff0c\u4e16\u754c\uff01'Hello,world![root@centos7~]#Redirection下面的描述中,如果省略数字n,第一个重定向操作符号为<,那么本次重定向指的是标准输入(文件描述符0),如果第一个重定向操作符号是>,则重定向指向标准输出(文件描述符1)。重定向运算符后面的词将被扩展。1.Inputredirection[n]wordword扩展后的结果文件会被命令的输出覆盖(文件不存在会创建)。内置命令集设置了noclobber选项的bash进程在使用重定向操作符>时不会覆盖以下文件。使用运算符>|强制覆盖。3、增加输出重定向[n]>>word4,重定向标准输出和标准错误&>word>&word,相当于>word2>&1。5、添加重定向标准输出和标准错误&>>word等同于>>word2>&16,以读写方式打开文件[n]<>word上面重定向中word的展开结果不能为多个,并且它只能是一个文件。多个重定向在命令中出现的顺序很重要,但重定向在命令中的位置无关紧要。#!/bin/bash#多次重定向出现的顺序有时会影响结果#标准输出和标准错误都重定向到文件filelshellofile>file2>&1#标准错误输出到终端,标准输出是重定向到文件lshellofile2>&1>file#重定向发生在哪里并不重要。下面三个命令是等价的:head-1>newfile>>newfilehead-1>newfile-1#查看验证catnewfileexecution:[root@centos7~]#./test.shls:无法访问hello:没有这样的文件或目录root:x:0:0:root:/root:/bin/bashroot:x:0:0:root:/root:/bin/bashroot:x:0:0:root:/root:/bin/bash7,HereDocuments<<[-]wordhere-documentdelimiter这里的word不能展开,如果word中的任何字符被引号(如previousreferencepart),delimiter是单词去掉引号后剩下的字符,here-document中的单词不会被shell解释。如果单词未被引用,则here-document中的单词可以进行变量扩展、命令替换和数学扩展(类似于双引号的情况)。如果重定向运算符是<<-,则here-document中的前导制表符将被删除。8.HereStrings<<file#文件的内容不会作为注释。变量不加引号时可以在文档中展开:$VARworldEOFcatfile#HereStringsecho${parameter:=$[`tr",""+"<<<"1,2,3"`]}#variabletemporaryscopeIFS=':'readaabbcc<<<"11:22:33"echo-e"$aa$bb$IFS$cc"执行结果:[root@centos7~]#./test.sh#文档内容不会作为注释,不引用时可以在文档中展开变量:helloworld6112233[root@centos7~]#9.Copyfiledescriptor[n]<&word#Copyinputfiledescriptor[n]>&word#复制输出文件描述符这里扩展word的值必须是一个数字,表示复制这个文件描述符到n,如果扩展word的结果不是文件描述符,就会出现重定向错误。如果word的值为-,表示关闭文件描述符n。[n]>&word这里有一个特例:如果省略了n,word的结果不是数字,表示重定向标准错误和标准输出(如前所述)。10、传输文件描述符[n]<&digit-#传输输入文件描述符[n]>&digit-#传输输出文件描述符这两个意思是将文件描述符位移动到文件描述符n,移动后文件描述符位关闭。由于bash中的重定向只在当前命令有效,所以命令执行后,重定向就被撤销了。使用exec内置命令可以使重定向在整个脚本中生效。脚本示例:#!/bin/bash#打开输入文件描述符3,并关联文件fileexec3./stdoutexec4>./stderr#将标准输出转移到3号描述符,关闭原来的1号文件描述符。exec1>&3-#将标准错误转移到4号描述符,并关闭原来的2号文件描述符。exec2>&4-#命令的标准输出会写入文件./stdout,标准错误会写入文件./stderrlsfilenewfile#关闭两个文件描述符exec3>&-#关闭时,重定向符号为>或<无所谓exec4<&-#定义远程主机和端口host=10.0.1.251port=80#以读写方式打开文件描述符5,并与文件关联(此文件表示到远程端的TCP链接)如果!exec5<>/dev/tcp/$host/$portthenexit1fi#测试链接可用性echo-e"GET/http1.1\n">&5#获取输出cat<&5#关闭文件描述符exec5<&-执行result:[root@centos7~]#./test.sh#我是文件内容&${ASYNC[1]}#读取时获取输出-u${ASYNC[0]}user_namedoecho$user_namedone执行结果:[root@centos7~]#./test.sh28653标准命令的输出和标准输入分别通过双向管道连接到当前shell的两个端口一个文件描述符,然后将文件描述符赋值给数组元素NAME[0]和NAME[1]rootbindaemon...[root@centos7~]#Pipeline管道是进程间通信的主要手段之一。Linux管道分为两种类型:匿名管道和命名管道。使用控制运算符|连接命令时创建的管道或|&是匿名管道。匿名管道只能在具有亲缘关系的进程之间使用。命名管道可以在两个不相关的进程之间使用,可以使用命令mknod或mkfifo来创建命名管道。我们见过很多匿名管道的例子。下面是一个使用命名管道来控制并发进程数的例子:|mkfifo$tmpfile#以读写方式打开文件描述符5,并关联命名管道exec5<>$tmpfile#删除临时命名管道文件rm$tmpfile#写入指定数量的空行供readwhile((NUM-->0))doechodone>&5forIPin`catip.list`do#read命令每次读取一行输入,保证后面的10条复合命令同时运行read{#StatisticsofIP在日志文件中出现的次数access.loggrep-c$IPaccess.log>>result.txtecho#命令运行后,向文件描述符写入一个空行5#Endsymbol&guarante此复合命令运行在后台}>&5&done<&5#内置命令wait的作用是等待子进程结束wait#关闭文件描述符5exec5>&-稍微执行。当然这里的for循环中执行的复合命令可以换成任何需要并发执行的任务。