shell脚本【符号2】I/O重定向相关符号

标签: I/O重定向 exec tee
29人阅读 评论(0) 收藏 举报
分类:

本篇博客用于介绍I/O重定向相关的符号和操作

 I/O重定向符号:>   <    >>    2>   1>   &1   &>

 1、概念:

        标准输入重定向:就是把命令的输入从默认的从键盘读取,重定向到一个文件: <file。

        标准输出重定向:就是把命令的标准输出保存到指定的文件内:>file   >>file   1>file。

        标准错误输出重定向:把命令的错误输出保存到指定文件内:2>file   2>>file。

        标准错误输出和标准输出均重定向到同一个文件的操作:

        1>file 2>&1  或   &>file   或  &>>file (其中>和>>的区别就是一个覆盖文件原内容,一个不覆盖。并且注意,是没有2>>&1这种写法的。        

2、区分:

     标准输出和标准错误输出不是包含关系,是两个独立的输出。相当于一个输出正常信息,一个输出出错信息。

     命令、shell脚本、判断(循环)语句块、shell函数等等,一切中间可以嵌套echo语句的或者本身就有输出的命令语句,都可以进行标准输入、标准输出、标准错误输出的I/O重定向。(可能这句话没有那么准确)

3、重定向过程:

       系统会打开一个默认的文件,用于标准输入、标准输出、标准错误输出指向文件。

       重定向后,系统会先关闭原指向文件,打开新文件,并把打开这个文件产生的指针重新装入进程文件表中。此时,文件描述符就更改了,更改为了指向新打开的这个文件的指针。所以,此时再用&1引用这个描述符,就是代表新打开的这个文件,而不是原系统默认文件。

4、如何输出

        我们知道在重定向到一个确定的文件后,标准输出和标准错误输出的信息就会打印进文件,而没有对应到了终端。有没有办法,让输出信息既打印进文件,同时又输出到终端呢?

        答案:有。

        方法1:tee命令。

        例如:bash test | tee filename

        分析:bash test命令的输出结果,通过管道传递给tee命令。tee命令一边把标准输出打印进文件filename,一边就输出信息到屏幕。(注意的是,管道不能传输标准错误输出:点击打开链接

        方法2:/dev/tty

        这种方法,如果重定向了脚本的标准输出和标准错误输出,通过>/dev/tty,可以将输出信息仍然能够送到用户的终端窗口,但是注意:输出到终端的这一句信息,不会再保存到文件内。

        顺便讲一下命令:exec,这个命令有两种用法,我们今天只讲它重定向的功能。

        exec命令加在脚本中,可以使这个脚本中其随后的所有命令的标准输入、标准输出、标准错误输出重定向。

        脚本例子test:

                echo hello

                exec >filename 2>errfilename     #exec命令加在这里,只对下面的所有命令有效果

                echo chenhaojie >/dev/tty          #加了exec命令后,如果想输出中间的某一句,可以使用这种方式

                echo WUST                                 #由于exec的作用,打印到filename文件,而不是终端

        执行:bash test

        终端屏幕输出;hello 

                              chenhaojie

        同时filename中的内容:WUST

        exec这个命令的方便之处在于:如果有个shell脚本是通过系统自动调用的,你并不知道这个脚本具体在哪被调用。所以,无法用添加“ | tee filename”这种方式来获得它的输出信息。如果你想获取这个脚本的输出信息,可以直接在这个脚本中进行修改,添加exec > filename 重定向命令,而无须知道,它是在哪个地方被调用。并且可以随意查看标准输出和标准错误输出信息。

        注意:加了>/dev/tty的命令,不会再把当句命令的输出信息保存到文件。

        方法1和方法2各有各的限制,方法1,无法保存错误信息,方法2,无法一边保存一边输出。

 

  本篇博客主要内容概述:

    接下来会举一个四个例子:例①、②、③、④

    主例为例①,然后针对例①出现的问题进行分析,并改进代码,例②③④都是对例①的精简和改进。例④最终会解决问题。

    对例①、②、③、④的一个概述

    例①、②、③、④分别用的重定向和出现的问题:

    例①:1>file   2>&1     

                问题:函数中有一句输出被覆盖

    例②:1>>file 2>&1  

                问题:例①出现的覆盖没有出现。但是,不能自动删除文本中原数据。

    例③:&>file  

                输出:和例①是一模一样的

    例④:1>file &>>file          (注意例④这种,和1>file 2>>file并不相等)

                结果:例①出现的覆盖问题没有出现。并且,每次更新文件时,可以自动删除原数据

   例 ① 脚本文件,利用1>test6 2>&1:

           脚本功能:实现shell函数I/O重定向的检测

           脚本文件:sum100

           脚本代码结构说明:其实就只包含了 两个shell函数 和 一个while语句块。其中function_testTwo函数是对function_testOne函数中出现问题的一个对比分析检测。因为这两个函数在最终的输出重定向时有点不同,one函数是在语句块结束后紧跟着就重定向,而two函数是在调用函数时,才重定向。two函数就是为了排除,在这一点上的区别对最终输出造成的影响。虽然结果显示,这两种并没有任何区别。

           代码如下:

                        number=1

                        sum=0

                        max=100

                        function_testOne()

                        {

                                read a b c                               #用于读取重定向到函数的文件内容

                                echo "输出测试${b}"

                                echo ${a}

                                echo chenhaojie>>test6         #这一句没有输出到文件

                                # echo chenhaojie> test6       #和上一句比较,这一种把前两句输出删了

                                echo ${*}                                #没有输出

                                echo ${1}                                #没有输出  

                                 ls –y                                      #错误命令行

                                 echo hello>>test6                #test6可以被写入,并且是在文本最后写入

                                #打开的文件,在写入时不会出问题吗,test6在函数运行期间没有一直打开吗

                        } >test2 1>test6 2>test4 2>&1      

                        function_testTwo( )                        #shell函数输入变量测试函数

                        {

                                echo `expr $1 + 8` >>test7   #没有输出,和前一个函数情况一样

                                echo $1

                                echo `expr $1 + 1` >>test7

                                #注意:是反引号,expr是求表达式的值,中间要加空格,至于不加空格的情况自己去查吧

                        }

                        while [ "$number" -le "$max" ]

                        do

                                let sum=$sum+$number

                                let number=$number+1

                                echo hello

                        done >test1                                   #while语句块的输出重定向

                        echo $sum

                        function_testOne  >test3  2>test5  <test8

                        #调用函数,并且测试调用函数后的输出重定向

                        function_testTwo 921  >test7         #数值921参数传递

                        exit 0


         执行命令:bash sum100

         说明:最终会建立七个用于输出的文件:test1、test2、test3、test4、test5、test6、test7。

            输入文件:test8,其内容为:1 2 3

         分析:

         test1文件:while语句块的输出重定向文件

         内容:很多行hello

            每循环一次,test1文件中就会在文本最后增加写入一行hello。

      分析:后一次写入并没有覆盖前一次写入,这说明什么?test1文件,怎样才会被重新写入?应该是关闭了再打开一 次,就重新写入。没有覆盖写入,说明在while语句块循环期间,test1文件一直是打开状态,直到循环结束。

         其实从shell命令解析过程也可以看出来,while语句块是当做一个整体被读入的。而I/O重定向是在解析的第六步就进行了,并不是等待命令执行,或者是执行完才I/O重定向,而是在命令执行的前几步就进行了。具体参见命令行解析过程:(等待一个链接

          test2文件,没有内容,但是会被创建。

      分析:先是>test2文件,所以,系统会先创建一个test2文件,打开这个test2文件,并把它的指针信息更新进进程文件表。但是,后一句: 1>test6,系统又把test2文件关闭,然后创建test6文件,打开它,并更新进程文件表信息。这里的文件描述符“1”更像是一个文件指针。&1用来指向test2文件,但是,这个指针随时都可以被改变(自我理解,不对,请指出^^)。

         test3文件,没有内容,但是会被创建。

        分析:之所以会被创建,理由和test2文件被创建的理由相当,命令被读入后,就会创建文件,并首先更新进程文件表。之所以没有内容,相比因为是,函数已经没有了输出。原因是,紧跟语句块后面的重定向已经把数据重定向,输出到文件了,所以,在后面调用函数时,就不会再有输出内容。

        这里有一个概念,出口状态和标准输出的区别,别把return ,exit等输出的出口状态,和标准输出弄混了:点击打开链接

        test4文件,没有内容,但是会被创建,同test2文件。

        test5文件,没有内容。同test3。

        test6文件,内容:函数function_testOne()的标准输出和标准错误输出都输出到了test6文件。

     问题的出现:函数中的最后一条命令echo hello >>test6标准输出,输出到了test6文件,在最后一句写入。中间的一句命令:echo chenhaojie>>test6没有输出,或者说输出被覆盖了。问题就是这两个。

     基本分析:>test2,是标准输出重定向到了test2文件;1>test6,把标准输出重定向到了test6文件;2>test4,是标准错误输出重定向到test4文件;2>&1,是标准错误输出重定向到文件描述符1指向的文件test6。所以,最终,这四句相当于:1>test6 2>&1

         test6文件要问的是:

         问1:为什么echo hello >>test6,可以被写入,并且为什么是在文本最后写入,而不是文本最开始。这一句应该是对test6最开始的写入,除非,函数里面的内容是一边输出一边写入。

               答:首先,为什么是在文本最后写入,而不是文本最开始。这里的疑惑的原因在于理解上有错误。

                     错误的理解,所有的输出都是在一个缓冲区,等待着函数块执行完,然后写入文件。所以,echo hello >>test6作为一句实际语句的命令输出,应该是最先被写入的。

                     然而根据命令行解析过程来看,最终的输出是按照命令执行的逻辑顺序依次输出的。也就是说,函数块中的语句是先执行,如果有输出,就有写入操作。所以,echo hello >>test6,最为最后执行的语句,当然是最后输出。

         问2:为什么echo hello >>test6可以输出,虽然是在文件最后。而中间的一句命令echo chenhaojie >>test6 没有输出到文件test6文件中。

              答:这一句应该也是有输出的,接在上一句的输出后面,只是被后一句给覆盖了。

                    如果用>test6来检测,会发现它把前两句给删掉了。

                    解释一下,为什么echo chenhaojie >test6这个命令会删掉原先数据。应该是,虽然文件已经被打开了,但是文件肯定是首先被,然后执行删除原数据操作。并非,文件打开了,就不能执行删除操作了。

                    而之所以被后一句覆盖了,应该是因为,他们的信息不对称导致的,在那一句命令独立输出后,函数指向并没有更新。或许上面的解释不准确,先留个坑吧,以后学Linux系统时,再回来看这里,先给一个多进程同时打开一个文件的分析博客:点击打开链接

        test7文件,内容921   922。

     分析:test7文件有内容,但是test3、test5文件没有内容。test3、test5文件没有内容的原因是function_testOne函数的输出已经被重定向到文件了,所以,在最后调用的时候,function_testOne函数已经没有输出了。

     函数function_testTwo中一条语句的输出922,也是写在test7文件的最后,这和function_testOne函数中的一条语句的输出,写在test6文件最后是一致的。

        test8文件,是输入文件。标准输入重定向文件。内容是1 2 3。通过read命令读入,并赋给参数a b c。

     执行完命令后,输出于屏幕内容,只有语句echo $sum,输出到屏幕的内容:5050。


     如果执行命令换成:bash sum100  >test1   (test1文件是while语句块的输出重定向文件)

        输出结果test1中的内容(while语句块的输出)并不会清除,只会把最开始的两行hello替换成5050。

     所以,为什么test1没有被清空的原因和上面在function_testOne函数中出现的情况应该是一样吧,但是,又有点不同,因为函数中把内容全部清掉了。

 

      例②: 对例子①的精简,并且更改,利用1>>test6  2>&1

        现在把上面的测试代码精简一下,并把原1>test6 2>&1,更改为1>>test6 2>&1:

            sum101脚本:

                        function_testOne()

                        {

                                read a b c              #用于读取输入重定向到函数的文件内容

                                echo "输出测试${a}"

                                echo ${b}

                                echo "string">>test6    #这一句没有输出到文件

                                ls -y            #错误输出

                                echo chenhaojie

                                echo ${*}               #没有输出

                                echo ${1}               #没有输出

                                ls –y                  #错误命令行

                                echo "hello">>test6     #test6可以被写入,并是在文本最后写入

                        } 1>>test6 2>&1                  #函数输出重定向到test6

                        function_testOne <test1

        执行命令:bash sum101

            test6文件的输出:

                  输出测试1

                            2

                            string

                            ls: invalid option -- 'y'

                            Try 'ls --help' for more information.

                            chenhaojie

 

 

                            ls: cannot access '–y': No such file or directory

                            hello

        分析:echo string >>test6 正常输出了,

            问题:但有一个问题,test6文件原内容也会保留。如何使test6文件原内容删除,又使echo string >>test6输出正常呢?看例④

 

       例③ :对例 ① 的等效更改,利用&>finlename

                对原脚本进行更改:

                                function_testOne()

                                {

                                        read a b c              #用于读取输入重定向到函数的文件内容

                                        echo "输出测试${a}"

                                        echo ${b}

                                        echo "string">>test6    #这一句没有输出到文件

                                        ls -y            #错误输出

                                        echo chenhaojie

                                        echo ${*}               #没有输出

                                        echo ${1}               #没有输出

                                        ls –y                  #错误命令行

                                        echo "hello">>test6     #test6可以被写入,并是在文本最后写入

                                } &>test6                  #函数输出重定向到test6

                                function_testOne <test1

          执行命令:bash sum101

                test6文件的输出:

                        输出测试1

                                      2

                                      ls: invalid option -- 'y'

                                      Try 'ls --help' for more information.

                                      chenhaojie

 

 

                                     ls: cannot access '–y': No such file or directory

                                     hello

         分析:和例①的结果是一样的。string字符串的输出被覆盖掉了。所以,这个&>test6的功能想必也猜到了,就是把标准输出stdout和标准错误输出stderr都重定向到test6文件。

                 &>test6等同于 1>test6 2>&1

 

        例④ :对例②进行更改,利用1>filename  &>>filename:

       把函数的输出重定向语句1>>test6  2>&1更改为1>test6  &>>test6,问题解决。

            脚本:

                            function_testOne()

                            {

                                    read a b c              #用于读取输入重定向到函数的文件内容

                                    echo "输出测试${a}"

                                    echo ${b}

                                    echo "string">>test6    #这一句没有输出到文件

                                    ls -y            #错误输出

                                    echo chenhaojie

                                    echo ${*}               #没有输出

                                    echo ${1}               #没有输出

                                    ls –y                  #错误命令行

                                    echo "hello">>test6     #test6可以被写入,并是在文本最后写入

                            } 1>test6 &>>test6          #函数输出重定向到test6

                            function_testOne <test1

 

            所以,1>test6 &>>test6是表示什么意思?中间做了什么?

           虽然最后这个问题解决了,但是,这中间的过程我还是没有弄懂。

           不过知道了一个很强的操作,就是1>filename  &>>filename,这个操作,不会漏掉任何信息,相对于其它操作都比较安全。

查看评论

bash shell脚本高级特性详解2

本课程为全新马哥linux全套系列课程之一--Linux基础入门和架构了解,从Linux起源,Linux架构和Linux形成历史开始逐步讲解,让你彻彻底底了解Linux的诞生,之后介绍了Linux相关文化和核心组成结构,以及Linux常用命令和基本用法,课程由浅入深,讲授方法受到98%学员一致好评!
  • 2015年04月16日 14:35

Shell I/O重定向的原理解释

在Unix系统中,每个进程都有STDIN、STDOUT和STDERR这3种标准I/O,它们是程序最通用的输入输出方式。几乎所有语言都有相应的 标准I/O函数 ,比如,C语言可以通过scanf从终端输入...
  • beautysleeper
  • beautysleeper
  • 2016-09-18 14:09:55
  • 681

关于I/O口符号

PIC单片机系列封装引脚最少的是8引脚(如PIC12C5XX和PIC12C6XX),多的可达84引脚(如 PIC17C76X),其中I/O(输入/输出)口线按PIC单片机产品型号不同,其口线数量也不相...
  • wangluojisuan
  • wangluojisuan
  • 2011-09-21 11:45:36
  • 1689

shell脚本中的一些符号

在shell中常用的特殊符号罗列如下:  # ;   ;; . , / \\ 'string'| !   $   ${}   $? $$   $*  \"string\"* **   ? ...
  • qq_31550425
  • qq_31550425
  • 2016-12-12 14:55:58
  • 740

linux Linux常见特殊符号 重定向符号

Linux中高级I/O 重定向的符号及其用法 符号 意义 n>&m 将FD为m的输出复制到FD为n的文件中 n ...
  • maimang1001
  • maimang1001
  • 2011-10-30 21:20:58
  • 6141

shell脚本学习--符号

一、shell简单介绍      shell的作用是解释执行用户的命令,用户输入一条命令,shell就解释一行【交互式】。另一种执行命令的方式是【批处理】,用户事先写一个shell脚本,其中有很多条...
  • Sekai_Z
  • Sekai_Z
  • 2016-08-14 21:10:19
  • 787

基本I/O接口电路设计实验

;***************根据CHECK配置信息修改下列符号值******************* IOY0 EQU 0A000H ;片选IOY0对应的端...
  • jbx929205249
  • jbx929205249
  • 2011-11-15 17:48:47
  • 1915

shell浅谈之八I/O重定向

一、简介       I/O重定向用于捕获一个文件、命令、程序或脚本甚至代码块的输出,然后把捕获到的输出作为输入发送给另外一个文件、命令、程序或脚本等。I/O重定向最常用的方法是管道(管道符"|...
  • taiyang1987912
  • taiyang1987912
  • 2014-09-24 21:02:12
  • 4692

Linux中的特殊符号-重定向符号

重定向符号:1、“>”或”1>”输出重定向:把前面输出的东西输入到后边的文件中,会清除文件原有的内容。[root@Simile /]# echo 'a a b b c c' >test.txt [ro...
  • u014360942
  • u014360942
  • 2017-05-22 21:26:51
  • 752

数学符号及读法

数学符号及读法 1 Α α alpha a:lf 阿尔法 角度;系数 2 Β β beta bet 贝塔 磁通系数;角度;系数 3 Γ γ gamma ga:m 伽马 电导系数(小写) 4...
  • chinaswin
  • chinaswin
  • 2016-03-10 09:47:20
  • 871
    个人资料
    持之以恒
    等级:
    访问量: 1998
    积分: 318
    排名: 23万+
    文章存档