zoukankan      html  css  js  c++  java
  • Linux程序设计 读笔2 Shell脚本

    第二章 Shell程序设计

    四、管道和重定向

    1 重定向输出

    ls -l > lsoutput.txt

    ps >> lsoutput.txt  >>表示附加到一个文件中

    文件描述符0:标准输入

    文件描述符1:标准输出

    文件描述符2:标准错误输出

    kill -HUP 1234 >killout.txt 2>killerr.txt   标准输出重定向到killout.txt中了;标准错误输出(文件描述符2)重定向到killerr.txt中了

    kill -l 1234 > killouterr.txt 2>&1  把两组输出都重定向到一个文件中了,使用>&来结合的,注意2和1的出现顺序!此处表示“将标准输出(1)重定向到killouterr.txt中,然后再将标准错误(2)输出到与标准输出相同的地方”

    2 管道

    可使用管道操作符|来连接进程

    如离散命令:

      ps > psout.txt

      sort psout.txt > pssort.out

    可以直接写为:

      ps | sort > pssort.out

    五、shell可以作为程序设计语言

    交互式程序 + 创建创建脚本 两种方式写shell程序

    1 交互式

      ls my_{finger,toe}s    列出文件my_fingers和my_toes

      grep -l POSIX * | more

    2 创建脚本

    例子:创建一个名为fisrt的shell脚本,完成的功能是:所有当前目录下内容包含“apple”字符串的文件,并打印出文件名字

    #! /bin/sh   #是一种特殊形式的注释,告知系统/bin/sh就是用来执行本文件的程序
    
    for file in *
    do 
        if grep -q apple $file
        then
            echo $file
        fi
    done
    
    exit 0

    有两种执行方式:

    方式1: $/bin/sh first  明确指出运行shell脚本的程序

    方式2:    

      $chmod +x first

      $./first

    六、shell的语法

    1 变量

    无需事先声明,通过加$符来访问变量的内容,默认所有变量都被看作字符串并以字符串来存储

    #a=7+5

    #echo $a

    7+5

    read命令可以将用户输入的值读给一个变量:

    #read var

    hello world

    #echo $var

    hello world

    关于变量中引号的使用:包括双引号、单引号 和 字符:

    #!/bin/sh
    
    myvar="Hi there"
    
    echo $myvar     
    echo "$myvar" 
    echo '$myvar'
    echo $myvar

    输出如下:

      Hi there

      Hi there

      $myvar

      $myvar

    环境变量(名字通常全大写):

      $HOME

      $PATH

      $PS1   命令提示符,通常是$

      $PS2   二级提示符,用来提示后续到输入,通常是>

      $IFS   输入域分割符。通常是空格、制表符、换行符

      $0    SHELL脚本的名字

      $#     传递给脚本的参数个数

      $$    SHELL脚本的进程号

    参数变量:

      $1, $2, ...   脚本程序的参数

      $*      在一个变量中列出所有的参数,各个参数之间用环境变量IFS中到第一个字符分割开

      $@      是$*的一种精巧的变体,它不使用IFS环境变量,所以即使IFS为空,参数也不会挤在一起

    例子:展示$@ 和 $*的区别

    $ IFS=''

    $ set foo bar bam

    $ echo "$@"

    foo bar bam

    $ echo "$*"

    foobarbam

    $ unset IFS

    $ echo "$@"

    foo bar bam      不使用IFS环境变量,所以即使IFS为空,参数也不会挤在一起

    使用参数和环境变量的例子:

    #!/bin/sh
    
    echo "The program $0 is now running"
    echo "The second parameter was $2"
    echo "The first parameter was $1"
    echo "The parameter list was $*"
    
    exit 0

    运行该脚本

    $ ./test foo bar baz

    The program ./test is now running

    The second parameter was bar

    The first parameter was foo

    The parameter list was foo bar baz

    2 条件

    条件测试使用test或者[]命令:

      if test -f fred.c    #-f 表示测试一个文件是否存在

      then

        ...

      fi

    等价于:

      if [ -f fred.c ]

      then

        ...

      fi

    举例:

    #!/bin/sh
    
    echo "The program $0 is now running"
    
    if [ -f /bin/bash ]; then
        #statements
        echo "file /bin/bash exists"
    fi
    
    if [ -d /bin/bash ]; then
        #statements
        echo "/bin/bash is a directory"
    else
        echo "/bin/bash is Not a directory"
    fi
    
    exit 0

    3 控制结构

    (1)if语句

    if condition

    then

      ...

    else

      ...

    fi

    (2)elif语句

    if condition

    then  

      ...

    elif condition

      ...

    else

      ...

    fi

    (2)for语句

    for variable in values

    do

      ...

    done

    实验1:

    #! /bin/sh
    
    for foo in bar fud 43
    do
        echo $foo
    done
    
    exit 0

    输出:

      bar

      fud

      43

    (3)while语句

    while condition

    do

      ...

    done

    (4)until语句

    until condition

    do

      ...

    done

    注:while是条件成立往下走,而until相反!

    (5)case语句

    case variable in

      pattern [ | pattern ] ...) statement;;

      pattern [ | pattern ] ...) statement;;

    esac

    case实例1:用户输入

    #! /bin/sh
    
    echo "Is it morning? Please answer yes or no"
    read timeofday
    
    case "$timeofday" in
        yes ) echo "Good Morning";;
        no ) echo "Good Afternoon";;
        y ) echo "Good Morning";;
        n ) echo "Good Afternoon";;
        * ) echo "Sorry, answer not recognized";;
    esac
    
    exit 0

    case实例2:合并匹配模式

    #! /bin/sh
    
    echo "Is it morning? Please answer yes or no"
    read timeofday
    
    case "$timeofday" in
        yes | y | Yes | YES ) echo "good morning";;
        n* | N* ) echo "good afternoon";;
        * ) echo "sorry";;
    esac
    
    exit 0

    case实例3:执行多条语句

    #! /bin/sh
    
    echo "Is it morning? Please answer yes or no"
    read timeofday
    
    case "$timeofday" in
        yes | y | Yes | YES )
            echo "good morning"
            echo "up bright and early this morning"
            ;;
        [nN]* )
            echo "good afternoon"
            ;;
        * )
            echo "sorry"
            echo "bad input"
            ;;
    esac
    
    exit 0

     (6)命令列表

    AND列表

      statement1 && statement2 && statement3 && ...    

      只有在前面所有命令都执行成功的情况下才执行后一条语句

    OR列表

      statement1 || statement2 || statement3 || ...

        只要有一条命令执行成功,后面的命令将不再执行!

    (7)语句块

      想在某些只允许使用单个语句的地方(如在AND或OR列表中)使用多条语句,就可以使用{}来构造一个语句块

    (8)一个与变量有关的问题

    例子:

      if [ $timeofday = "yes" ]

      then

        echo "good morning"

      ...

      ...

      假如$timeofday为空,则if中的条件变成了:if [ = "yes" ],而这不是一个合法条件,因此程序报错,而应该尽量写成:

      if [ "$timeofday" = "yes" ]   上面的例子中都是这么写的,要注意!!!

    4 函数

    function_name(){

      statements

    }

    实例:演示参数传递以及函数返回值

    #! /bin/sh
    
    yes_or_no(){
    
        echo "Is your name $* ?"
        while [ true ]; do
            echo -n "Enter yes or no: "
            read x
            case "$x" in
                y | yes ) return 0;;
                n | no ) return 1;;
                * ) echo "Answer yes or no";;
            esac
        done
    }
    
    echo "Original parameters are $*"
    
    if yes_or_no "$1"; then
        echo "Hi $1, nice name"
    else
        echo "Never mind"
    fi
    
    exit 0

    5 命令

    (1)break命令  仅在for、while、until中用

    (2)命令  空命令,偶尔被用于简化条件逻辑,相当于true的别名

    (3) continue命令   仅在for、while、until中用

    (4).命令  用于在当前shell中执行命令

    (5)echo命令   echo命令默认末尾有换行符,欲去掉可以用 echo -n

    (6)eval命令  允许你对参数进行求值

        foo=10

        x=foo

        y='$'$x

        echo $y  此时会输出$foo

        foo=10

        x=foo

        eval y='$'$x

        echo $y  此时会输出10

    (7)exec命令

      用法1:典型用法:将当前shell替换为一个不同的程序

        exec wall 'thanks' 脚本中的这个命令会用wall命令替换当前的shell。脚本中exec后面的代码都不会执行,因为执行这个脚本的shell都已经不存在了

      用法2:修改当前文件描述符(很少见)

    (8)exit n命令  使脚本以退出码n结束运行

      退出码0表示成功,退出码1~125是脚本程序可用的错误代码,其余数字具有保留含义

    (9)export命令  将作为它参数的变量导出到子shell中,并使之在子shell中有效。

      一般,在一个shell中被创建的变量在这个shell调用的子shell中是不可用的。

      

      注:一旦一个变量被shell导出,它就可以被该shell调用的任何脚本使用,也可以被后续依次调用的任何shell使用。本例若export2再调用了另一个脚本,bar的值对新脚本来说仍有效!

    (10)expr命令  将其参数当做一个表达式来求值

        x=1

        x=$x+1

        echo $x     会输出1+1,不是我们想要的!

        

        x=1  

        x=`expr $x + 1`  特别注意这里是反引号,而非单引号,键盘上容易打错!

        echo $x    输出2,√

        

        x=1  

        x=$(expr $x + 1)

        echo $x    输出2,√

      

        如今在新脚本程序中,expr被替换为更有效的$((...))语法:

        x=1  

        x=$(($x + 1))

        echo $x      输出2,√

    (11)printf命令  格式化输出

        printf "%s %d %s" "Hi There" 15 people

    (12)return命令

    (13)set命令   为shell设置参数变量

        echo the date is $(date)  输出 the date is Sun Dec 13 14:32:28 EST 2015

        set $(date)

        echo the month is $2  输出 the month is Dec

    (14)shift命令 把所有参数变量左移一个位置,使$2变为$1,$3变为$2,原来$1的值被丢弃而$0不变  

    #! /bin/sh
    
    while [ "$1" != "" ]; do
        echo "$1"
        shift
    done
    exit 0

      若执行 ./test 1 2 3 4 5,则会输出:

      1

      2

      3

      4

      5

    (15)trap命令 用于指定在接收到信号后将要采取的行动

      trap -l 查看信号编号及其关联的名称

      trap command signal   #command表示接收到signal信号时将要采取的行动  

    (16)unset命令 从环境中删除变量和函数。 不常用

    (17)find命令(不属于shell)  搜索文件

      find [path] [options] [tests] [actions]

    举例:

      find / -name test -print  从根目录/开始搜索名字为test的文件并print出来

      find . -newer while2 -print   在当前目录下搜索比while2要新的文件

      find . -newer while2 -type f -print 在上一个命令的基础上进行约束,使结果仅包含普通文件

      find . ( -name "_*" -or -newer while2 ) -type f -print 

    (18)grep命令(不属于shell) 通用正则表达式解析器,可使用其在文件中搜索字符串

      grep [options] PATTERN [FILES]

    举例:

      grep in words.txt    在words.txt中搜索字符串in

      grep -c in words.txt words2.txt  在两个不同的文件中计算匹配行的数目

      grep -c -v in words.txt words2.txt 使用-v选项进行取反,在两个文件中计算不匹配行的数目

    (19)正则表达式

    先举几个例子:

      grep e$ words2.txt   查找以e结尾的行

      grep a[[:blank:]] words2.txt  查找以a结尾的单词

      grep Th.[[:space:]] words2.txt  查找以Th开头的由3个字母组成的单词

      grep -E [a-z]{10} words2.txt  搜索只有10个字符长的全部由小写字母组成的单词

      

    6 命令的执行

    (1)算术扩展

      expr命令也可以执行一些算术命令,但慢,因为其需要调用一个新的shell来处理expr命令

      替代办法:$((...))   把准备求值的表达式放在其中

    (2)参数扩展

    for i in 1 2; do
         my_secret_process $i_tmp   不行,不认识$i_tmp
    done

    需写成:

      my_secret_process ${i}_tmp

    7 here文档

    here文档可以在shell脚本中用于向一条命令传递数据:

      cat << !FUNKY!

      hello

      this is a here

      document

      !FUNKY!

    输出:

      hello

      this is a here

      document

    七、迈向图形化:dialog工具

  • 相关阅读:
    AcWing
    The Preliminary Contest for ICPC Asia Nanjing 2019
    2004-2005 ACM-ICPC Southeastern European Regional Programming Contest (SEERC 2004)
    自考新教材-p352_1
    自考新教材-p351_4
    自考新教材-p350_3
    自考新教材-p350_2
    自考新教材-p349_3(1)
    自考新教材-p347
    自考新教材-p346
  • 原文地址:https://www.cnblogs.com/hansonwang99/p/4940960.html
Copyright © 2011-2022 走看看