zoukankan      html  css  js  c++  java
  • 笔记高级Bash脚本编程指南

    这本电子书在电脑里已经有段时间了,虽然平时写点shell没问题,但是感觉还是不精,就拿这本书查漏补缺吧.

    注: 脚本例子大部分引用原书

    就从12章开始吧

    cat , tac , rev

    cat test                   tac test                 rev test
    
    123                            789                       321
    456                            456                       654
    789                            123                       987
    

    expr

    通用求值表达式: 通过给定的操作(参数必须以空格分开)连接参数, 并对参数求值. 可以使算术操作, 比较操作, 字符串操作或者是逻辑操作.
    
    expr 3 + 5
    返回8
    
    expr 5 % 3
    返回2
    
    expr 1 / 0
    返回错误消息, expr: division by zero
    
    不允许非法的算术操作.
    
    expr 5 \* 3
    返回15
    
    在算术表达式expr中使用乘法操作时, 乘法符号必须被转义.
    
    y=`expr $y + 1`
    增加变量的值, 与let y=y+1和y=$(($y+1))的效果相同. 这是使用算术表达式的一个例子.
    
    z=`expr substr $string $position $length`
    在位置$position上提取$length长度的子串.
    

    date

    # date --date='1 days ago'   
    2011年 05月 06日 星期五 21:04:58 CST
    # date --date='1 days ago' +%Y%m%d
    20110506
    

    join

    join命令只能够操作两个文件. 它可以将那些具有特定标记域(通常是一个数字标签)的行合并起来, 并且将结果输出到stdout. 被加入的文件应该事先根据标记域进行排序以便于能够正确的匹配.

      1 File: 1.data
      2 
      3 100 Shoes
      4 200 Laces
      5 300 Socks
    ------------------------------
      1 File: 2.data
      2 
      3 100 $40.00
      4 200 $1.00
      5 300 $2.00
    ------------------------------
    
     bash$ join 1.data 2.data
     File: 1.data 2.data
    
     100 Shoes $40.00
     200 Laces $1.00
     300 Socks $2.00
    
    mktemp
    使用一个"唯一"的文件名来创建一个临时文件. 如果不带参数的在命令行下调用这个命令时, 将会在/tmp目录下产生一个零长度的文件.
    [root@bash]# mktemp -p /home/ abc.XXXXX
    /home/abc.V2113
    
    seq
    [root@bash ~]# for num in $(seq 10);do echo $num;done 
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    
    wall
    bash$ wall System going down for maintenance in 5 minutes!
    Broadcast message from bozo (pts/1) Sun Jul  8 13:53:27 2001...
    
     System going down for maintenance in 5 minutes!
    	      
    
    命令替换 算术扩展
    使用后置引用的算术扩展(通常都是和expr一起使用)
     z=`expr $z + 3`          # 'expr'命令将会执行这个扩展.
    
    后置引用形式的算术扩展已经被双括号形式所替代了 -- ((...))和$((...)) -- 当然也可以使用非常方便的let结构.
    
    1 z=$(($z+3))
      2 z=$((z+3))                                  #  也正确. 
      3                                             #  使用双括号的形式, 
      4                                             #+ 参数解引用
      5                                             #+ 是可选的. 
      6 
      7 # $((EXPRESSION))是算数表达式.              #  不要与命令替换
      8                                             #+ 相混淆. 
      9 
     10 
     11 
     12 # 使用双括号的形式也可以不用给变量赋值. 
     13 
     14   n=0
     15   echo "n = $n"                             # n = 0
     16 
     17   (( n += 1 ))                              # 递增. 
     18 # (( $n += 1 )) is incorrect!
     19   echo "n = $n"                             # n = 1
     20 
     21 
     22 let z=z+3
     23 let "z += 3"  #  使用引用的形式, 允许在变量赋值的时候存在空格. 
     24               #  'let'命令事实上执行得的是算术赋值, 
     25               #+ 而不是算术扩展. 
    
    第九章 操作字符串
    字符串长度
      1 stringZ=abcABC123ABCabc
      2 
      3 echo ${#stringZ}                 # 15
      4 echo `expr length $stringZ`      # 15
      5 echo `expr "$stringZ" : '.*'`    # 15
    提取子串
    ${string:position:length} 或者 expr substr $string $position $length
      1 stringZ=abcABC123ABCabc
      2 #       0123456789.....
      3 #       0-based indexing.
      4 
      5 echo ${stringZ:0}                            # abcABC123ABCabc
      6 echo ${stringZ:1}                            # bcABC123ABCabc
      7 echo ${stringZ:7}                            # 23ABCabc
      8 
      9 echo ${stringZ:7:3}                          # 23A
     10                                              # 提取子串长度为3.
     11 
     12 
     13 
     14 # 能不能从字符串的右边(也就是结尾)部分开始提取子串? 
     15     
     16 echo ${stringZ:-4}                           # abcABC123ABCabc
     17 # 默认是提取整个字符串, 就象${parameter:-default}一样.
     18 # 然而 . . .
     19 
     20 echo ${stringZ:(-4)}                         # Cabc 
     21 echo ${stringZ: -4}                          # Cabc
     22 # 这样, 它就可以工作了.
     23 # 使用圆括号或者添加一个空格可以"转义"这个位置参数.
    
    子串削除
    ${string#substring}    从$string开头位置截掉最短匹配的$substring.
    ${string##substring}   从$string开头位置截掉最长匹配的$substring.
      1 stringZ=abcABC123ABCabc
      2 #       |----|
      3 #       |----------|
      4 
      5 echo ${stringZ#a*C}      # 123ABCabc
      6 # 截掉'a'到'C'之间最短的匹配字符串.
      7 
      8 echo ${stringZ##a*C}     # abc
      9 # 截掉'a'到'C'之间最长的匹配字符串.
    

    ${string%substring}    从$string结尾位置截掉最短匹配的$substring.
    ${string%%substring}  从$string结尾位置截掉最长匹配的$substring.
      1 stringZ=abcABC123ABCabc
      2 #                    ||
      3 #        |------------|
      4 
      5 echo ${stringZ%b*c}      # abcABC123ABCa
      6 # 从$stringZ的结尾位置截掉'b'到'c'之间最短的匹配.
      7 
      8 echo ${stringZ%%b*c}     # a
      9 # 从$stringZ的结尾位置截掉'b'到'c'之间最长的匹配. 
    
    子串替换
    ${string/substring/replacement}  使用$replacement来替换第一个匹配的$substring.
    ${string//substring/replacement}  使用$replacement来替换所有匹配的$substring.
      1 stringZ=abcABC123ABCabc
      2 
      3 echo ${stringZ/abc/xyz}           # xyzABC123ABCabc
      4                                   # 使用'xyz'来替换第一个匹配的'abc'.
      5 
      6 echo ${stringZ//abc/xyz}          # xyzABC123ABCxyz
      7                                   # 用'xyz'来替换所有匹配的'abc'.
    
    ${string/#substring/replacement}  如果$substring匹配$string开头部分, 那么就用$replacement来替换$substring.
    ${string/%substring/replacement}  如果$substring匹配$string结尾部分, 那么就用$replacement来替换$substring.
      1 stringZ=abcABC123ABCabc
      2 
      3 echo ${stringZ/#abc/XYZ}          # XYZABC123ABCabc
      4                                   # 用'XYZ'替换开头的'abc'.
      5 
      6 echo ${stringZ/%abc/XYZ}          # abcABC123ABCXYZ
      7                                   # 用'XYZ'替换结尾的'abc'.
    

    printf

    [root@x1 ~]# for num in $(seq 10);do printf '%02d\n' $num ;done
    01
    02
    03
    04
    05
    06
    07
    08
    09
    10
    
    注意: printf '%02d\n' (这之间必须有空格)$num 
    

    正则表达式 re

    grep -E '\<22\>|\<15\>' secure
    

    转义的"尖括号" -- \<...\> -- 用于匹配单词边界.

    尖括号必须被转义才含有特殊的含义, 否则它就表示尖括号的字面含义.

    "\<the\>" 完整匹配单词"the", 不会匹配"them""there""other", 等等.

    扩展的正则表达式

    • 问号 -- ? -- 匹配它前面的字符, 但是只能匹配1次或0次. 通常用来匹配单个字符.

    • 加号 -- + -- 匹配它前面的字符, 能够匹配一次或多次. 与前面讲的*号作用类似, 但是不能匹配0个字符的情况.

    • 转义"大括号" -- \{ \} -- 在转义后的大括号中加上一个数字, 这个数字就是它前面的RE所能匹配的次数.大括号必须经过转义, 否则, 大括号仅仅表示字面含意.
    • 圆括号 -- ( ) -- 括起一组正则表达式. 当你想使用expr进行子字符串提取(substring extraction)的时候, 圆括号就有用了. 如果和下面要讲的"|"操作符结合使用, 也非常有用.

    • 竖线 -- | -- 就是RE中的"或"操作符, 使用它能够匹配一组可选字符中的任意一个.

    POSIX字符类. [:class:]

    • [:alnum:] 匹配字母和数字. 等价于A-Za-z0-9.

    • [:alpha:] 匹配字母. 等价于A-Za-z.

    • [:blank:] 匹配一个空格或是一个制表符(tab).

    • [:cntrl:] 匹配控制字符.

    • [:digit:] 匹配(十进制)数字. 等价于0-9.

    • [:graph:] (可打印的图形字符). 匹配ASCII码值范围在33 - 126之间的字符. 与下面所提到的[:print:]类似, 但是不包括空格字符(空格字符的ASCII码是32).

    • [:lower:] 匹配小写字母. 等价于a-z.

    • [:print:] (可打印的图形字符). 匹配ASCII码值范围在32 - 126之间的字符. 与上边的[:graph:]类似, 但是包含空格.

    • [:space:] 匹配空白字符(空格和水平制表符).

    • [:upper:] 匹配大写字母. 等价于A-Z.

    • [:xdigit:] 匹配16进制数字. 等价于0-9A-Fa-f.

    22. 进程替换
    用圆括号扩起来的命令

    >(command)

    <(command)

    启动进程替换. 它使用/dev/fd/<n>文件将圆括号中的进程处理结果发送给另一个进程. [1] (译者注: 实际上现代的UNIX类操作系统提供的/dev/fd/n文件是与文件描述符相关的, 整数n指的就是进程运行时对应数字的文件描述符)

    进程替换可以比较两个不同命令的输出, 甚至能够比较同一个命令不同选项情况下的输出.

    bash$ comm <(ls -l) <(ls -al)
    total 12
    -rw-rw-r--    1 bozo bozo       78 Mar 10 12:58 File0
    -rw-rw-r--    1 bozo bozo       42 Mar 10 12:58 File2
    -rw-rw-r--    1 bozo bozo      103 Mar 10 12:58 t2.sh
            total 20
            drwxrwxrwx    2 bozo bozo     4096 Mar 10 18:10 .
            drwx------   72 bozo bozo     4096 Mar 10 17:58 ..
            -rw-rw-r--    1 bozo bozo       78 Mar 10 12:58 File0
            -rw-rw-r--    1 bozo bozo       42 Mar 10 12:58 File2
            -rw-rw-r--    1 bozo bozo      103 Mar 10 12:58 t2.sh
    

    为了让函数可以返回字符串或是数组, 可以使用一个在函数外可见的专用全局变量.

    在函数被调用之前, 所有在函数中声明的变量, 在函数体外都是不可见的, 当然也包括那些被明确声明为local的变量.

      1 count_lines_in_etc_passwd()
      2 {
      3   [[ -r /etc/passwd ]] && REPLY=$(echo $(wc -l < /etc/passwd))
      4   #  如果/etc/passwd是可读的, 那么就把REPLY设置为文件的行数. 
      5   #  这样就可以同时返回参数值与状态信息. 
      6   #  'echo'看上去没什么用, 可是 . . .
      7   #+ 它的作用是删除输出中的多余空白字符. 
      8 }
      9 
     10 if count_lines_in_etc_passwd
     11 then
     12   echo "There are $REPLY lines in /etc/passwd."
     13 else
     14   echo "Cannot count lines in /etc/passwd."
     15 fi  
    

    26. 数组

    Bash支持一维数组. 

    声明数组

    array[10]=     #初始化一个空数组元素
    
    array=(1 2 3 4 5)     #有5个元素
    declare -a array     #也是声明一个数组
    echo ${array[1]}     #调用数组元素,下标从0开始计算
    array_name=([xx]=XXX [yy]=YYY ...)
    area3=([17]=seventeen [24]=twenty-four)   #另一种初始化并赋值的方法
    echo ${array[@]}  #打印数组所有元素
    echo ${array[*]}   #同上

    打印一首小诗

    Line[1]="I do not know which to prefer,"
    Line[2]="The beauty of inflections"
    Line[3]="Or the beauty of innuendoes,"
    Line[4]="The blackbird whistling"
    Line[5]="Or just after."
    
    for index in 1 2 3 4 5    # 5行. 
     do
       printf "     %s\n" "${Line[index]}"
     done
    

    数组操作

    array=( one two three four five five )
    
    echo ${#array[0]}    和 echo ${#array}    #第一个数组元素长度
    
    echo ${#array[*]}    和 echo ${#array[@]}    #数组元素个数
    
    #提取数组子串
    
    echo ${arrayZ[@]:0}     # one two three four five five
                                          # 所有元素. 
    echo ${arrayZ[@]:1}     # two three four five five
                            # element[0]后边的所有元素. 
    echo ${arrayZ[@]:1:2}   # two three
                             # 只提取element[0]后边的两个元素. 
    

    bash使用C语言语法的for循环

    #!/bin/bash
    for ((i=0;i<6;i++));
    do
      echo $i
    done
    
    #结果
    0
    1
    2
    3
    4
    5
    

    29. 调试

    sh -n scriptname不会运行脚本, 只会检查脚本的语法错误. 

    sh -v scriptname将会在运行脚本之前, 打印出每一个命令.

    sh -x scriptname会打印出每个命令执行的结果, 但只使用缩写形式.

      #在大括号包含的代码块中, 最后一条命令没有以分号结尾.
      1 { ls -l; df; echo "Done." }
      2 # bash: syntax error: unexpected end of file
      3 
      4 { ls -l; df; echo "Done."; }
      5 #                        ^     ### 最后的这条命令必须以分号结尾. 
    

  • 相关阅读:
    代码审计之越权及越权
    代码审计之XSS及修复
    代码审计之SQL注入及修复
    代码审计之CSRF原理及修复
    挖穿各大SRC的短信轰炸
    Kerberoasting攻击
    SPN扫描
    Windows认证 | 域认证
    Windows认证 | 网络认证
    Ceph 纠删码介绍
  • 原文地址:https://www.cnblogs.com/txwsqk/p/2040123.html
Copyright © 2011-2022 走看看