shell浅谈之八I/O重定向
来源:互联网 发布:玩游戏防闪退软件 编辑:程序博客网 时间:2024/04/27 14:37
一、简介
I/O重定向用于捕获一个文件、命令、程序或脚本甚至代码块的输出,然后把捕获到的输出作为输入发送给另外一个文件、命令、程序或脚本等。I/O重定向最常用的方法是管道(管道符"|")。
二、详解
1、管道
(1)管道技术是Linux间的一种通信技术,利用先进先出排队模型来指挥进程间的通信(可当作连接两个实体的一个单向连接器)。Linux管道可用于应用程序之间、linux命令之间、应用程序与命令间的通讯。shell编程指利用管道进行Linux命令之间的通信。
管道通信的格式:command1 | command2 | command3 | ... | commandn,command1执行后如果没有管道则输出结果直接显示在shell上,当shell遇到管道符"|"后会将command1的输出发送到command2作为command2的输入。
例:ls -l | grep vi | wc -l,在三个命令之间建立两根管道,第一个命令ls -l的输出作为grep vi 的输入,第二个命令在管道输入下执行后的输出作为第三个命令wc -l的输入,第三个命令在管道输入下执行命令将结果输出到shell。这是一个半双工通信,因通信是单向的,则两个命令之间的具体工作是由linux内核来完成的。
(2)sed、awk和管道
sed、awk可以从文件读取输入数据,也可以从管道获得输入数据。
sed命令的格式是:| sed [选项] 'sed命令',表示sed对管道输入的数据进行处理。例:ls -l | sed -n '1,5p',表示打印ls -l命令结果的第1~5行。例:cat passwd | sed -n '/root/p' | sed -n '/login/p',查找文件中包含root和login两个关键字的行。例:variable1="Hello world";variable2=`echo $variable1 | sed "s/world/Sir/g"`;echo $variable2,对变量中字符串进行替换。
awk的命令格式是:| awk [-F 域分隔符] 'awk程序段'(可以用awk代替expr的使用),例:echo $string | awk '{print length($0)}',计算string字符串的长度。echo $string | awk '{print substr($0, 1, 8)}',抽取string字符串中第1~8个字符作为字串输出。
注意:管道将字符串作为awk的输入数据时,awk将管道输入当作输入文件。awk可以解析变量名,但这必须要在该变量从管道输入的情况下,如上若字符串变量不从管道输入时,awk无法解析变量名。
awk使用管道,例:awk -F ':' '{print $1 | "sort"}' /etc/passwd,awk将分隔符指定为冒号,将打印结果通过管道传输给sort命令进行排序,然后输出。特别注意的是awk中调用Linux命令时需要用双引号将这些命令引起来。
awk处理shell命令输出,需要引入getline函数将shell命令的输出保存到变量中,awk再对该变量进行处理。例:awk 'BEGIN{while (("ls /usr" | getline data) > 0) print data}',awk在BEGIN字段中使用了while循环将ls /usr命令的结果逐个传给getline data,并打印data变量,直到ls /usr命令的结果全部处理结束。例:df -k | awk '$4 > 1000000',df -k列出文件系统控件信息,第四个域是剩余空间量,输出可用空间大于1GB的文件系统。
对shell命令结果进行处理,必须将结果通过管道传给getline函数,如果结果较多则要使用循环。也可以不将shell命令放在awk内部,awk同样也可以对shell命令进行处理。
2、I/O重定向
(1)I/O重定向是一个过程,这个过程捕捉一个文件、命令、程序或脚本,甚至代码块的输出,然后把捕捉到的输出作为输入发送给另外一个文件、命令、程序或脚本。(2)文件描述符
文件描述符是从0开始到9的结束的整数,指明了与进程相关的特定数据流的源。当Linux系统启动一个进程(该进程可能用于执行shell命令)时,将自动为该进程打开三个文件:标准输入(文件标识符为0)、标准输出(1标识)和标准错误输出(2标识),若要打开其他的输入或输出文件则从整数3开始标识。默认情况下,标准输入与键盘输入相关联,标准输出与标准错误输出与显示器相关联。
Shell从标准输入读取输入数据,将输出送到标准输出,如果该命令在执行过程中发生错误,则将错误信息输出到标准错误输出。
tee命令将shell的输出从标准输出复制一份到文件中,tee命令加-a表示追加到文件的末尾。
(3)I/O重定向符号
I/O重定向符号分为:基本I/O重定向符号和高级I/O重定向符号(与exec命令有关)。
基本I/O重定向符号及其意义如下:
>|符号是强制覆盖文件的符号,如果noclobber选项开启(set -o noclobber),表示不允许覆盖任何文件,此时>|可强制将文件覆盖。n>> file、n>|file与n>file都是将FD为n的文件重定向到file文件中。
<是I/O重定向的输入符号,它可将文件内容写到标准输入之中。wc -l < newfile,其中shell从命令行会“吞掉”<newfile并启动wc命令。
<<delimiter(delimiter为分界符),该符号表明:shell将分界符delimiter之前的所有内容作为输入,cat > file << FIN,输入FIN后按回车键结束编辑,输入内容重定向到file文件中。其另一种形式:-<<delimiter,在<<前加一个负号,这样输入文本行所有开头的"Tab"键都会被删除,但开头的空格键却不会被删除,如cat > file -<< FIN。
高级I/O重定向符号及其意义:
(4)exec命令
exec命令可以通过文件描述符打开或关闭文件,也可将文件重定向到标准输入及将标准输出重定向到文件。
- #使用exec将stdin重定向到文件
- #!/bin/bash
- exec 8<&0 #FD 8是FD 0的副本,用于恢复标准输入
- exec < file #将标准输入重定向到file
- read a #读取file的第一行
- read b #读取file的第二行
- echo "----------------"
- echo $a #标准输出
- echo $b #标准输出
- echo "close FD 8:"
- #exec 0<&8 8<&- #将FD 8复制到FD 0,恢复FD 0,并关闭FD 8,其他进程可以重复使用FD 8
- echo -n "Enter Data:"
- read c #read从标准输入读取数据
- echo $c
- #exec将标准输出从定向到文件
- #!/bin/bash
- exec 8>&1 #FD 8是FD 1的副本,用于恢复FD 1
- exec > log #将标准输出重定向到log,>符号等价于1>符号
- echo "Output of date command:"
- date #date和df命令
- echo "Output of df command:"
- df
- exec 1>&8 8>&- #FD 8复制到FD 0,FD 0恢复为标准输出,并关闭FD 8
- echo "--------------------------------"
- cat log #查看log文件
- # &>file将stdout和stderr重定向到文件
- #!/bin/bash
- exec 8>&1 9>&2 #FD 1复制到FD 8,FD 2复制到FD 9
- exec &> log #&>符号将stdout和stderr重定向到文件log
- ls z* #错误写入文件log
- date #输出写入文件log
- exec 1>&8 2>&9 8<&- 9<&- #恢复关闭操作
- echo "-----------------"
- echo "Close FD 8 and 9:"
- ls z*
- date
代码块重定向是指在代码块内将标准输入或标准输出重定向到文件,而在代码块之外还是保留默认状态。可以重定向的代码块可以是while、until、for等循环结构、可以是if/then测试结构、还可以是函数。代码块输入重定向符号是<,输出重定向符号是>。
while循环的重定向:
- #while循环的重定向
- #!/bin/bash
- ls /etc > log #将ls /etc的结果写到log文件中
- while [ "$filename" != "rc.d" ] #搜索log文件中第一次与rc.d匹配的行,并输出行数
- do #不匹配时,执行while循环体
- read filename
- let "count +=1"
- done < log #将while代码块的标准输入重定向到log文件
- echo "$count times read" #测试循环体外的标准输入是否被重定向
- echo -n "-----Input Data:-----"
- read test #最终是从标准输入获取数据
- echo $test
- #for循环的重定向
- #!/bin/bash
- ls /etc > log #将ls /etc的结果写到log文件中
- maxline=$(wc -l < log) #计算log文件的最大行数,赋给maxline
- for filename in `seq $maxline` #seq命令产生循环参数,相当于for filename in 1,2,...,maxline
- do
- read filename #按行读取log文件数据
- if [ "$filename" = "rc.d" ] #if指定跳出循环的条件
- then
- break
- else
- let "count +=1" #不匹配,计数器count加1
- fi
- done < log #for代码块中将标准输入重定向到log文件
- echo "$count:times read"
- echo -n "-----Input Data:-----" #测试for外标准输入是否被重定向
- read test
- echo $test
- #if/then结构的输出重定向
- #!/bin/bash
- if [ -z "$1" ] #如果位置参数$1为空
- then
- echo "Positional Parameter is NULL" #将该语句重定向输入到log文件
- fi > log #if/then代码块输出重定向到log文件
- echo "------Normal Stdout --------" #代码块外的标准输出是否被重定向
3、命令行处理
(1)流程
shell从标准输入或脚本读取的每一行称为管道(pipeline),每一行包含一个或多个命令,这些命令用管道符隔开,shell对每一个读取的管道处理流程如下(命令行的处理步骤是由shell自动完成。):
例如在/root目录下输入:echo ~/i* $PWD `echo hello world` $((21*20)) > output,shell处理该命令步骤:
1)shell首先将命令行分割成令牌(令牌以元字符分隔),> output虽被识别但它不是令牌。
2)检测第一个单词echo是否为关键字,echo不是开放关键字,命令行继续。
3)检测echo是否为别名,echo不是,命令行继续。
4)扫描命令行是否需要花括号展开,该命令无花括号,则命令行继续处理。
5)扫描命令行是否需要波浪号展开,存在则展开:echo /root/i* $PWD `echo hello world` $((21*20))。
6)扫描命令行中是否存在变量,若存在则替换,存在PWD,命令行变为:echo /root/i* /root`echo hello world` $((21*20)) 。
7)扫描命令行中是否存在反引号,若存在则替换,存在则命令行变为:echo /root/i* /roothello world $((21*20)) 。
8)执行命令行中的算术运算,则命令行变为:echo /root/i* /roothello world 420 。
9)shell对前面所有展开所产生的结果进行再次扫描,依据$IFS对结果进行单词分割。
10)扫描命令行中的通配符并展开,展开后命令行变为:echo /root/install.log /root/install.log.syslog /root hello world 420。
11)此时,shell已经准备执行命令了,它寻找echo(echo是内建命令)。
12)shell执行echo,此时执行>output的I/O重定向。
上图中从执行命令步骤跳转到初始步骤,这正是eval命令的作用。eval命令将其参数作为命令行,让shell重新执行该命令行。eval在处理简单命令时,与直接执行该命令无区别。如果变量中包含任何需要shell直接在命令中看到的字符,就需要使用eval命令。命令结束符(;,|,&)、I/O重定向符(<和>)及引号这些对shell具有特殊意义的符号,必须直接出现在命令行中。
- #eval重新提交shell
- #!/bin/bash
- while read NAME VALUE #第一列作为变量名,第二列作为变量值
- do
- eval "${NAME}=${VALUE}" #第1轮变量替换,eval重新提交shell完成赋值操作
- done < evalsource #输入重定向
- echo "var1=$var1" #变量赋值
- echo "var2=$var2"
- echo "var3=$var3"
- echo "var4=$var4"
- echo "var5=$var5
- shell浅谈之八I/O重定向
- shell浅谈之八I/O重定向
- shell浅谈之八I/O重定向
- shell------ I/O 重定向
- Shell I/O重定向
- Linux shell I/O重定向详解
- Linux shell I/O重定向详解
- Linux shell I/O重定向详解
- Linux shell I/O重定向详解
- Linux shell I/O重定向详解
- Linux shell I/O重定向详解
- Linux shell I/O重定向详解
- Linux shell I/O重定向--进阶
- Linux shell I/O重定向详解
- Linux shell I/O重定向详解
- Linux shell I/O重定向详解
- linux shell I/O 重定向
- shell I/O重定向 1
- 华为机试—约瑟夫环
- shell中各种括号的作用()、(())、[]、[[]]、{}
- C# 中值类型和引用类型的区别
- HDU 5155 Harry And Magic Box(组合+容斥)
- Jsp连接MSSQL数据库
- shell浅谈之八I/O重定向
- 网络爬虫技术浅析
- 迭代器概念
- Sencha Extjs的官网在线API
- shell浅谈之七文本处理工具grep、sed、awk
- 【转自oschina网站】Hadoop、Pig、Hive、Storm、NOSQL 学习资源收集
- 统计中的各种技巧
- C#序列化与反序列化
- 碰撞器和触发器更新