zoukankan      html  css  js  c++  java
  • shell脚本学习之6小时搞定(6)重定向及其他 Marathon

    shell学习之-重定向及其他


    Unix 命令默认从标准输入设备(stdin)获取输入,将结果输出到标准输出设备(stdout)显示。一般情况下,标准输入设备就是键盘,标准输出设备就是终端,即显示器。

    1.输出重定向

    命令的输出不仅可以是显示器,还可以很容易的转移向到文件,这被称为输出重定向

    命令输出重定向的语法为:

    command > file
    

    这样,输出到显示器的内容就可以被重定向到文件。

    例如,下面的命令在显示器上不会看到任何输出:

    who > users
    

    打开 users 文件,可以看到下面的内容:

    # cat users
    
    oko         tty01   Sep 12 07:30
    ai          tty15   Sep 12 13:32
    ruth        tty21   Sep 12 10:10
    pat         tty24   Sep 12 13:07
    steve       tty25   Sep 12 13:03
    

    输出重定向会覆盖文件内容,请看下面的例子:

    echo line 1 > users
    
    cat users
    line 1
    

    如果不希望文件内容被覆盖,可以使用>>追加到文件末尾,例如:

    echo line 2 >> users
    
    cat users
    line 1
    line 2
    

    2.输入重定向

    和输出重定向一样,Unix 命令也可以从文件获取输入,语法为:

    command < file
    

    这样,本来需要从键盘获取输入的命令会转移到文件读取内容。

    注意:输出重定向是大于号(>),输入重定向是小于号(<)。

    例如,计算 users 文件中的行数,可以使用下面的命令:

    wc -l users
    2 users
    

    也可以将输入重定向到 users 文件:

    wc -l < users
    2
    

    注意:上面两个例子的结果不同:第一个例子,会输出文件名;第二个不会,因为它仅仅知道从标准输入读取内容。

    3.重定向深入讲解

    一般情况下,每个 Unix/Linux 命令运行时都会打开三个文件:

    标准输入文件(stdin):stdin的文件描述符为0,Unix程序默认从stdin读取数据。
    标准输出文件(stdout):stdout 的文件描述符为1,Unix程序默认向stdout输出数据。
    标准错误文件(stderr):stderr的文件描述符为2,Unix程序会向stderr流中写入错误信息。
    #默认情况下,command > file 将 stdout 重定向到 file,command < file 将stdin 重定向到 file。
    

    如果希望 stderr 重定向到 file,可以这样写:

    command 2 > file
    

    如果希望 stderr 追加到 file 文件末尾,可以这样写:

    command 2 >> file
    

    2 表示标准错误文件(stderr)。

    如果希望将 stdoutstderr 合并后重定向到 file,可以这样写:

    command > file 2>&1
    

    如果希望对 stdinstdout 都重定向,可以这样写:

    command < file1 >file2
    

    command 命令将 stdin 重定向到 file1,将 stdout 重定向到 file2

    全部可用的重定向命令列表:

    命令	说明
    command > file	将输出重定向到 file。
    command < file	将输入重定向到 file。
    command >> file	将输出以追加的方式重定向到 file。
    n > file	将文件描述符为 n 的文件重定向到 file。
    n >> file	将文件描述符为 n 的文件以追加的方式重定向到 file。
    n >& m	将输出文件 m 和 n 合并。
    n <& m	将输入文件 m 和 n 合并。
    << tag	将开始标记 tag 和结束标记 tag 之间的内容作为输入。
    

    Here Document
    Here Document 目前没有统一的翻译,这里暂译为嵌入文档。Here Document 是 Shell 中的一种特殊的重定向方式,它的基本的形式如下:

    command << delimiter
        document
    delimiter
    

    它的作用是将两个 delimiter 之间的内容(document) 作为输入传递给 command。

    注意: 结尾的delimiter 一定要顶格写,前面不能有任何字符,后面也不能有任何字符,包括空格tab 缩进。

    开始的delimiter前后的空格会被忽略掉。

    下面的例子,通过 wc -l 命令计算 document 的行数:

    wc -l << EOF
        This is a simple lookup program
        for good (and bad) restaurants
        in Cape Town.
    EOF
    

    输出: 3

    也可以 将 Here Document 用在脚本中,例如:

    #!/bin/bash
    cat << EOF
    This is a simple lookup program
    for good (and bad) restaurants
    in Cape Town.
    EOF
    

    运行结果:

    This is a simple lookup program
    for good (and bad) restaurants
    in Cape Town.
    

    4./dev/null 文件

    如果希望执行某个命令,但又不希望在屏幕上显示输出结果,那么可以将输出重定向到 /dev/null

    command > /dev/null
    

    /dev/null 是一个特殊的文件,写入到它的内容都会被丢弃;如果尝试从该文件读取内容,那么什么也读不到。但是 /dev/null 文件非常有用,将命令的输出重定向到它,会起到禁止输出的效果。

    如果希望屏蔽 stdout 和 stderr,可以这样写:

    command > /dev/null 2>&1
    

    这样不会在屏幕打印任何信息。
    /dev/null 2>&1

    类型	                  文件描述符	默认情况	                  对应文件句柄位置
    标准输入(standard input)	0	从键盘获得输入	          /proc/self/fd/0
    标准输出(standard output)	1	输出到屏幕(即控制台)	  /proc/self/fd/1
    错误输出(error output)	        2	输出到屏幕(即控制台)	  /proc/self/fd/2
    
    # >/dev/null
    
    这条命令的作用是将标准输出1重定向到/dev/null中。 /dev/null代表linux的空设备文件,所有往这个文件里面写入的内容都会丢失,
    俗称“黑洞”。那么执行了>/dev/null之后,标准输出就会不再存在,没有任何地方能够找到输出的内容。
    
    # 2>&1
    这条命令用到了重定向绑定,采用&可以将两个输出绑定在一起。这条命令的作用是错误输出将和标准输出
    同用一个文件描述符,说人话就是错误输出将会和标准输出输出到同一个地方。
    
    linux在执行shell命令之前,就会确定好所有的输入输出位置,并且从左到右依次执行重定向的命令,所以>/dev/null 2>&1的
    作用就是让标准输出重定向到/dev/null中(丢弃标准输出),然后错误输出由于重用了标准输出的描述符,所以错误输出也被定向
    到了/dev/null中,错误输出同样也被丢弃了。执行了这条命令之后,该条shell命令将不会输出任何信息到控制台,也不会有任何
    信息输出到文件中。
    
    命令	            标准输出	错误输出
    >/dev/null 2>&1	      丢弃	丢弃
    2>&1 >/dev/null	      丢弃	屏幕
    

    Shell文件包含
    像其他语言一样,Shell 也可以包含外部脚本,将外部脚本的内容合并到当前脚本。

    Shell 中包含脚本可以使用 . filenamesource filename

    两种方式的效果相同,简单起见,一般使用点号(.),但是注意点号(.)和文件名中间有一空格。

    示例: 被包含文件:sub.sh

    name="yjc"
    主文件:test.sh
    
    . ./sub.sh
    echo $name
    

    运行结果:

    yjc
    

    获取当前正在执行脚本的绝对路径
    正确的命令是:

    basepath=$(cd `dirname $0`; pwd)
    

    直接使用pwd或者dirname $0是不对的。

    按特定字符串截取字符串
    示例:截取/www/html/php/myapp/里的myapp。

    方案:

    str=/www/html/php/myapp/
    b=($(echo $str|sed 's#/# #g'))
    b_len=`expr ${#b[*]} - 1`
    app_name=${b[$b_len]}
    echo $app_name
    

    这里利用sed将字符串按指定字符截成数组,然后取最后一个。

    计算数组长度:${#arr[*]}
    计算则需要使用expr命令

    5.awk

    awk简介
    awk是一个强大的文本分析工具,相对于grep的查找,sed的编辑,awk在其对数据分析并生成报告时,显得尤为强大。简单来说awk就是把文件(或其他方式的输入流, 如重定向输入)逐行的读入(看作一个记录集), 把每一行看作一条记录,以空格(或\t,或用户自己指定的分隔符)为默认分隔符将每行切片(类似字段),切开的部分再进行各种分析处理。

    awk有3个不同版本: awknawkgawk,未作特别说明,一般指gawkgawk 是 AWK 的 GNU 版本。

    Awk基本语法: 

    awk 'pattern1 {command1;command 2…; command 3}  pattern2 { command …}'
    

    pattern表示用来过滤记录的模式,可是是正则表达式,关系运算表达式,也可以什么也没有(表示选中所有记录)。

    每个pattern选中的行记录会被花括号括起来的命令command操作一遍, command之间用;分割。 花括号里面可以什么也没有, 则默认为print输出整行记录。 Comamnd可以是输出, 可以是算术运算,逻辑运算,循环控制等等。

    示例
    s.txt

    zhangsan 1977 male computer 83
    lisi 1989 male math 99
    wanglijiang 1990 female chinese 78
    xuliang 1977 male economic 89
    xuxin 1986 female english 99
    wangxuebing 1978 male math 89
    lichang 1989 male math 99
    wanglijiang 1990 female chinese 78
    zhangsansan 1977 male computer 83 
    langxuebing 1978 male math 89
    lisibao 1989 male math 99
    xiaobao 1990 female chinese 78
    

    一行中的5个字段分别表示姓名, 出生年, 性别,科目,分数, 是一个很传统很典型的报表文件。

    现在演示awk是如何查找的:

    1)直接输出1990年出生的同学:

    $ awk '/1990/' s.txt
    
    wanglijiang 1990 female chinese 78
    wanglijiang 1990 female chinese 78
    xiaobao 1990 female chinese 78
    

    或者:

    $ awk '/1990/{print $0}' s.txt
    awk默认把输入的内容以空格拆分出每列。$0表示匹配所有列,print $0将输出所有列,每列分隔符是空格。
    

    2)对chinese的课程的行输出"语文":

    $ awk '/chinese/{print "语文"}' s.txt
    
    语文
    语文
    语文
    

    3)记录的头部和结尾加上一段说明:

    $ awk 'BEGIN{print "Result of the quiz:\n"}{print $0}END{print "------"}' s.txt
    Result of the quiz:
    
    zhangsan 1977 male computer 83
    lisi 1989 male math 99
    wanglijiang 1990 female chinese 78
    xuliang 1977 male economic 89
    xuxin 1986 female english 99
    wangxuebing 1978 male math 89
    lichang 1989 male math 99
    wanglijiang 1990 female chinese 78
    zhangsansan 1977 male computer 83
    langxuebing 1978 male math 89
    lisibao 1989 male math 99
    xiaobao 1990 female chinese 78
    ------
    

    AWK工作流程:逐行扫描文件,从第一行到最后一行,寻找匹配特定模式的行,并在这些行上进行用户想要到的操作。

    BEGIN只会在最开始执行;END只会在扫描所有行数之后执行。BEGIN和END之间的花括号的内容每扫描一行都会执行。

    4)查找女生的成绩且只输出姓名、学科、成绩:

    $ awk '$3=="female"{print $1,$4,$5}' s.txt
    wanglijiang chinese 78
    xuxin english 99
    wanglijiang chinese 78
    xiaobao chinese 78
    $1表示第1列,$n类推。这里条件是表达式,而不是正则。print里,表示空格分隔符。
    

    5)找出1990年出生的学生姓名,并要求匹配正则:

    $ awk '$2~/1990/{print $1}' s.txt
    wanglijiang
    wanglijiang
    xiaobao
    这里~表示匹配正则表达式。!~表示不匹配正则表达式。
    

    如果需要多选,则改成:

    $ awk '$2~/(1990|1991)/{print $1}' s.txt
    

    awk更多内容详见:https://www.cnblogs.com/52fhy/p/5836429.html#autoid-3-4-0
    整理自:https://github.com/Daviswenpy/shell-book/blob/master/chapter6.md

  • 相关阅读:
    Global 文件中挂接HttpModule事件的方法列表参考
    百行代码打造一个DI容器(支持瞬时生命周期、单利生命周期、构造函数自动注入、属性自动注入、字段自动注入)
    松耦合服务调用利器服务分发器
    架构视角面面观之: WebPage能支持DI注入那该多好
    架构视角面面观之: WebPage能像MVC的ViewPage那样支持泛型节约不少代码量的?
    安装 Nuget 插件过程以及注意事项
    给Web Api 再加把柴让它更火起来
    Mini 容器泛型类型的使用
    JAVA虚拟机08垃圾回收HotSpot的算法实现细节
    Web UI 设计(网页设计)命名规范
  • 原文地址:https://www.cnblogs.com/davis12/p/14252573.html
Copyright © 2011-2022 走看看