shell脚本学习笔记一

作者: Java面试官 | 来源:发表于2017-11-25 16:36 被阅读61次

    一、前言

    使用shell写脚本也写了很多次了,不过大部分都是要用到了谷歌用法然后来的,没有比较全面的一次学习,这次趁着有些时间从头开始学一次shell脚本,也新建了一个新的文集,作为学习笔记使用,shell脚本大神请绕道哈~

    二、基本的io重定向

    标准io也就是标准的输入输出,这个可能是软件设计原则里边最普遍最重要的概念了,shell提供了集中语法标记,用来改变默认的io端,就是输入端和输出端。在这里还将说到一个强大的命令 -- tr

    以 < 改变标准输入: program < file 可将 program 的标准输入修改为 file,如:(shell_demo是路径)

    先查看我本地名交 wc_test 的文件内容:

    ➜  shell_demo vim  wc_test
     ls | wc -l
    ~                                                                               
    ~                                                                               
    ~         
    
    

    可以看到内容是 ls ......

    再使用tr命令,将wc_test定义为标准输入,并且将其中的内容的ls删除并且打出删除后的结果,命令如下:

    ➜  shell_demo tr -d 'ls' < wc_test
      | wc -
    

    从输出的结果可以看出,wc_test的内容被删除了ls并且打印了出来。

    使用 > 改变标准输出: program > file 可将program的标准输出修改为file,在上面的命令上进行再次的修改:

    ➜  shell_demo tr -d 'ls' < wc_test > wc_test2
    

    此处是将wc_test的内容被删除了ls之后再将其输入到wc_test2中,此处可以通过vim查看内容,并且要注意一点的是,在同目录下本来是没有wc_test2这个文件的,但是后来却新建了一个,说明重定向符在目的文件不存在时会新建一个,并且如果目的文件存在了,则原有内容会被覆盖掉。

    那么,在日常需求中,也会不覆盖文件,而是附加内容的需求存在,那么怎么做呢?

    shell提供了 >> 附加命令,program >> file 可将program的标准输出附加到file的结尾处,注意的是,如果文件不存在则会新建一个,如果存在了,则不会覆盖原有文件,而是将程序所产生的数据附加到文件末尾处,还是在原有的命令上进行修改:

    ➜  shell_demo tr -d 'ls' < wc_test >> wc_test2
    

    使用vim查看wc_test2可以发现内容已经变成了这样:

      | wc -
      | wc -
    ~        
    

    标准输入和输出都讲到了,接下来要说说如何将输入和输出连接在一起,也就是管道,shell 以 | 建立管道,即program1 | program2 ,可将program1的标准输出修改为program2的标准输入,为了看到效果,我先将wc_test里边的内容修改为:

    ls
    9
    8     
    7
    6
    5   
    4   
    3
    2
    1
    1
    2
    3
    4
    

    在采用tr命令将ls字符删除,并且将删除后的数据用通道的形式变成第二个程序的标准输入,命令如下:

    ➜  shell_demo tr -d 'ls' < wc_test | sort > wc_test3
    

    通过vim查看wc_test3的数据可以发现,数据是是wc_test中去掉ls后的内容并且是排好序的。

    tr的作用异常强大,具备对标准输入的字符压缩、替换删除的作用,具体的可以查看 http://man.linuxde.net/tr ,此处便不做详解。

    sort的作用是排序,可惜的是针对每行进行排序,具体的可以查看 http://man.linuxde.net/sort ,此处便不做详解。

    这里有个知识点想提及,在ubuntu系统中经常会遇见的一个问题,那就是修改root密码,如何做到修改密码的时候不打印键盘输入的字符,这里先给出一份脚本,再来讲解知识点,命令如下所示:

    #!/bin/sh
    printf "请输入密码:"
    stty -echo
    read pass < /dev/tty
    printf "\n" 
    printf "请再输入密码:"
    read pass2 < /dev/tty  
    stty echo
    printf "\n"           
    

    以上是我新建的一个名字叫 wc_test4.sh 的脚本文件,运行后可以看到类似修改root密码的时候输入字符终端却不打印出字符的效果,和这种效果有关的一个知识点,那就是/dev/tty,当程序打开此文件时,unix会自动将它重定向到终端,而stty(set tty)命令就是用来控制终端的各种设置,比如 stty -echo 的作用就是设置终端不打印出字符,当然了使用结束后用stty echo 来恢复该功能。

    三、新学的脚本命令

    ➜  ~ ls
    examples.desktop  Snapshots  模板  图片  下载  桌面
    npm-debug.log     公共的     视频  文档  音乐
    

    理解备注:这是查询本地目录的一个命令。

    但是有时候会衍生另一种需求:查看文件夹下面的文件和文件夹个数(同一目录下的),命令如下:

    ➜  ~ ls | wc -l
    11
    

    理解备注:在这里利用的是wc字数统计程序,可以算出行数、字数与字符数,| (管道)符号可以在两程序之间建立管道,ls的输出,成了wc的输入,wc所列出的结果就是目录下文件和文件夹的个数。

    有时候会遇见一种情况,需要将命令放进独立的脚本文件里,为了方便以后直接使用,可以尝试一下的方法:

    ➜  cat > wc_test
    

    输入以下命令:(可以替换为你想放进独立脚本的如何命令)

     ls | wc -l
    

    这里输入后记得以 ctrl+d 结束输入!

    之后就是添加执行权限~

    ➜  chmod +x wc_test
    

    运行输出

    ➜  ./wc_test 
    

    执行了这个脚本程序之后,会随之诞生一个问题, 那就是在执行这个shell脚本的时候,内核是如何执行这个过程的?

    当shell要求内核执行这个脚本时,内核讲无法执行这件事,并回应“not executable format file”错误信息,意思就是说这个不是内核可执行的格式文件,shell收到此错误信息之后,就会认为这不是编译程序,那么一定是shell脚本,接着就会启动一个新的/bin/sh(标准的shell)副本来执行程序。
    

    当系统只有一个shell时,退回到/bin/sh的机制很方便,但是现在的unix系统都会拥有好几个shell,因此告知unix内核是哪个shell来执行所指定的shell脚本就有必要了,那么怎么做呢?方法是在脚本的第一行设置,采用#!来开头,例如在我的go微服务项目(https://github.com/wiatingpub/MTBSystem)中的脚本:

    #!/bin/sh
    
    
    if [ $1 == "all" ]; then
        for srv in `ls src`; do
            if [[ ${srv:0-4} == "-srv" ]]; then
                echo "开始更新$srv"
                GOROOT=/data/services/go GOBIN=/data/goapp/mtbsystem/bin GOPATH=`pwd`:`pwd`/vendor /data/services/go/bin/go install $srv && sudo supervisorctl restart $srv:*
            fi
        done
    else
        for srv in "$@"
        do
            if [[ "${srv:0-4}" != "-srv" ]]; then
                srv="${srv}-srv"
            fi
            echo "开始更新$srv"
            GOROOT=/data/services/go GOBIN=/data/goapp/mtbsystem/bin GOPATH=`pwd`:`pwd`/vendor /data/services/go/bin/go install $srv && sudo supervisorctl restart class-$srv:*
        done
    fi
    
    

    ps:今天一边学习一边思考人生,也扔了个漂流瓶记录了下想法,希望未来能做个行动派,像我现在这样的年纪,更多的是想的多,做的少~

    有兴趣的可以关注我的个人公众号 ~

    qrcode_for_gh_04e57fbebd02_258.jpg

    相关文章

      网友评论

        本文标题:shell脚本学习笔记一

        本文链接:https://www.haomeiwen.com/subject/bazbvxtx.html