zoukankan      html  css  js  c++  java
  • Bash编程(6) String操作

    1. 拼接

      1) 简单的字符串拼接如:PATH=$PATH:$HOME/bin。如果拼接的字符串包含空格或特殊字符,需要使用双引号括起,如:

    var=$HOME/bin  # 注释并不是赋值的一部分
    var="$HOME/bin # but this is"
    
    # bash 3.1后,可以使用+=拼接(+=也可用于数组相加)
    var=abc
    
    $ var=abc
    $ var+=xyz
    $ echo "$var"
    abcxyz

    注意:+=的性能较直接拼接的效率高,测试如下:

    $ var=; time for i in {1..10000}; do var=${var}foo; done;
    
    real    0m1.251s
    user    0m1.144s
    sys    0m0.104s
    $ var=; time for i in {1..10000}; do var+=foo; done;
    
    real    0m0.156s
    user    0m0.156s
    sys    0m0.000s 

    2) 重复字符到指定长度

    _repeat(){
        #@ 功能:重复字符串到指定长度
        _REPEAT=
        while (( ${#_REPEAT} < $2))
        do
            _REPEAT+=$1
        done
    }
    
    $ _repeat % 40
    $ printf "%s
    " "$_REPEAT"
    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

      通过拼接在每个循环中拼接多个实例来提高函数速度:

    _repeat(){
        #@ 功能:重复字符串到指定长度
        _REPEAT=$1
        while (( ${#_REPEAT} < $2))
        do
            _REPEAT=$_REPEAT$_REPEAT$_REPEAT
        done
        _REPEAT=${_REPEAT:-:$2}  ##  裁剪指定长度字符串
    }
    
    repeat(){
        _repeat "$@"
        printf "%s
    " "$_REPEAT"
    }
    
    alert(){ #@ 功能: 打印包含边界及鸣响的警告信息
    _repeat "${2:-#}" $(( ${#1} + 8 ))
    printf 'a%s
    ' "$_REPEAT" ## a = BEL
    printf '%2.2s %s %2.2s
    ' "$_REPEAT" "$1" "$_REPEAT"
    printf '%s
    ' "$_REPEAT"
    
    }
    
    $ alert "Do you really want to detele all your files?"
    
    #################################################################################
    ## Do you really want to detele all your files? ##
    #################################################################################

     2. 字符处理

     没有直接的参数扩展来提供字符串的首字符或尾字符,可借助通配符问号?,以及字符串截取来抽取首字符或尾字符。

    $ var=strip
    $ allbutfirst=${var#?}  # 去除首字符
    $ allbutlast=${var%?}   # 去除尾字符
    $ printf "%8s %8s
    " "$allbutfirst" "$allbutlast"
        trip     stri
    $ first=${var%"$allbutfirst"} 
    $ last=${var#"$allbutlast"}
    $ printf "%8s %8s
    " "$first" "$last"
    s p
    
    ## 小测试
    $ while [ -n "$var" ]; do temp=${var#?}; char=${var%"$temp"}; printf "%s
    " "$char"; var=$temp; done ## 将字符串的每个字母按行打印
    s
    t
    r
    i
    p 
    $ while [ -n "$var" ]; do temp=${var%?}; char=${var#"$temp"}; printf "%s
    " "$char"; var=$temp; done  ## 将字符串的每个字母反向打印
    p
    i
    r
    t
    s 
     也可以通过"%c"获取字符串首字符
    $ printf -v first "%c" "$var"  # 将原本输出到标注输出的信息赋值给first
    $ echo $first
    s

    3. 大小写转换

    Bourne shell中,字符转换可以通过tr命令完成,tr作用:将第一个参数中的字符转换成对应的第二个参数中的字符

    $ echo abcdefgh | tr ceh CEH  ## c=>C,e=>E,h=>H
    abCdEfgH
    $ echo abcdefgh | tr ceh HEC ## c=>H,e=>E,h->C
    abHdEfgC
    $ echo touchdown | tr 'a-z' 'A-Z' ## 将小写转换为大写
    TOUCHDOWN 

    POSIX shell中,可以通过参数扩展来完成。

    to_upper(){
        case $1 in
            a*) _UPR=A;; b*) _UPR=B;; c*) _UPR=C;; d*) _UPR=D;;
            e*) _UPR=E;; f*) _UPR=F;; g*) _UPR=G;; h*) _UPR=H;;
            i*) _UPR=I;; j*) _UPR=J;; k*) _UPR=K;; l*) _UPR=L;;
            m*) _UPR=M;; n*) _UPR=N;; o*) _UPR=O;; p*) _UPR=P;;
            q*) _UPR=Q;; r*) _UPR=R;; s*) _UPR=S;; t*) _UPR=T;;
            u*) _UPR=U;; v*) _UPR=V;; w*) _UPR=W;; x*) _UPR=X;;
            y*) _UPR=Y;; z*) _UPR=X;; *) _UPR=${1%${1#?}};;
       esac
    }
    
    $word=function
    $to_upper "$word"
    $printf "%c%s
    " "$_UPR" "${word#?}"
    Function
    
    ## 将所有字符转换为大写
    _upword(){
        local word=$1
        while [ -n "$word" ]  ## 循环直到$word为空
        do
            to_upper "$word"
            _UPWORD=$_UPWORD$_UPR
            word=${word#?}  ## 移除$word中的首字母
        done
    }
    
    upword(){
        _upword "$@"
        printf "%s
    " "$_UPWORD"
    }

     4. 比较内容且不需考虑大小写

    当输入为单个字母,例如请求Y或N,可以使用逻辑运算符或(|)或者方括号([])对大小写进行选择。

    read ok
    case $ok in
        y|Y) echo "Great!" ;;
        n|N) echo Good-bye; exit 1 ;;
        *)  echo Invalid entry ;;
    esac
    
    
    read ok
    case $ok in
        [yY]) echo "Great!" ;;
        [nN]) echo Good-bye; exit 1 ;;
        *)  echo Invalid entry ;;
    esac 

     当输入较长时,以上方法需要将所有的可能组合进行展示,这样的方法较为繁琐。

    ## 针对于"|",需要列出所有组合
    jan | jaN | jAn | jAN | Jan | JAn | JAN) echo "Great!" ;;
    
    ## 对于"[]",脚本不宜阅读
    read monthname
    case $monthname in
        [Jj][Aa][Nn]*) month=1 ;;
        [Ff][Ee][Bb]*) month=2 ;;
        ## 输入剩余的月份
        [Dd][Ee][Cc]*) month=12 ;;
        [1-9]1[0-2] month=$monthname ;; 考虑输入数字的情况
        *) echo "Invalid month: $monthname" >&2 ;;
    esac 
    较好的方法是将输入统一转换为大写或小写再进行比较:
    _upword "$monthname"
    case _UPWORD in
        JAN*) month=1 ;;
        FEB*) month=2 ;;
       ## 输入剩余的月份
       DEC*) month=12 ;;
       [0-9]|1[0-2]) month=$monthname
       *) echo "Invalid month: $monthname" >&2 ;;
    esac
    bash 4.*中字符转换为大写,也可采用${monthname^^}执行

     5. 检查变量名的有效性

    检查变量名是否满足仅包含字母、数字和下划线,且只能以字母和下划线开头。

    validname(){
        case $1 in
            [!a-zA-Z_]* | *[!a-zA-Z0-9_]*) return 1;;
        esac
    }
    
    for name in name1 2var first.name first_name last-name
    do
        validname "$name" && echo " valid: $name" || echo "invalid: $name"
    done
    
    valid: name1
    invalid: 2var
    invalid: first.name
     valid: first_name
    invalid: last-name 

     6. 字符串插入

    _insert_string(){ #@功能: 在字符串的指定位置插入字符串
        local insert_string_dflt=2  ## 默认的插入位置
        local string=$1    ## 被插入的字符串
        local i_string=$2  ## 待插入字符串
        local i_pos=${3:-${insert_string_dflt:-2}}  ## 插入位置
        local left right
        left=${string:0:$(( $i_pos -1 ))}
        right=${string:$(( $i_pos -1 ))}
        _insert_string=$left$i_string$right
    }
    
    insert_string(){
        _insert_string "$@" && printf "%s
    " "$_insert_string"
    }
    
    $ insert_string poplar u 4
    popular
    $ insert_string show ad 3
    shadow
    $ insert_string tail ops ## 使用默认位置
    topsail

         7. 覆盖

    在一个字符串上覆盖另一个字符串。

    _overlay(){
        local string=$1
        local sub=$2
        local start=$3
        local left right
        left=${string:0:start-1}
        right=${string:start+${#sub}-1}
        _OVERLAY=$left$sub$right
    }
    
    overlay(){
        _overlay "$@" && printf "%s
    " "$_OVERLAY"
    }
    
    $ {
    > overlay pony b 1
    > overlay pony u 2
    > overlay pony s 3
    > overlay pony d 4
    > }
    bony
    puny
    posy
    pond 

    8. 裁剪不想要的字符

    字符串首尾的空格可以通过循环和条件判断完成。

    var="    John    "
    while : ## 无限循环
    do
        case $var in
            ' '*) var=${var#?} ;; ## 如果字符串以空格开始,则移除
            *' ') var=${var%?} ;; ## 如果字符串以空格结尾,则移除
            *) break; ## 当字符串的头部或尾部均无空格,则退出循环
         esac
    done 

    更有效的方法是找到首尾最长待删除的空格,然后从原始字符串中删除。

    var="    John    "
    printf "%s|%s
    " "$var" "${#var}"
    rightspaces=${var##*[! ]} ## 删除一切直到最后一个非空值
    printf "%s|%s
    " "$rightspaces" ${#rightspaces}  ## rightspaces为4个空格
    var=${var%"$rightspaces"} ## var目前为"John    "
    printf "%s|%s
    " "$var" "${#var}"
    leftspaces=${var%%[! ]*} ## 从第一个非空值删除直到结尾
    printf "%s|%s
    " ${leftspaces} ${#leftspaces}
    var=${var#"$leftspaces"}
    printf "%s|%s
    " "$var" "${#var}" 

     进一步封装的方法如下:如果存在第二个参数,则从字符串中删除该参数对应的字符,如果为空,则默认删除空格。

    _trim(){ #@ 从$1中删除空格(或$2中的字符)
       local trim_string
        _TRIM=$1
        printf "%s|%s
    " "$_TRIM" ${#_TRIM}
        trim_string=${_TRIM##*[!${2:- }]}
        printf "%s|%s
    " "$trim_string" ${#trim_string}
        _TRIM=${_TRIM%"$trim_string"}
        printf "%s|%s
    " "$_TRIM" ${#_TRIM}
        trim_string=${_TRIM%%[!${2:- }]*}
        printf "%s|%s
    " "$trim_string" ${#trim_string}
        _TRIM=${_TRIM#"$trim_string"}
        printf "%s|%s
    " "$_TRIM" ${#_TRIM}
    }
    
    trim(){
        _trim "$@" && printf "%s
    " "$_TRIM"
    }
    
    $ trim " S p a c e d o u t "
    S p a c e d o u t
    $ trim "0002367.45000" 0
    2367.45 

    9. 索引

    定位一个字符串在另一个字符串中的索引位置。

    _index(){ #@ $2在$1中的位置保存在$_INDEX
       local idx
       case $1 in
            "") _INDEX=0; return 1 ;;
            *"$2"*) idx=${1%%"$2"*}  ## 提取匹配位置的起始
                    _INDEX=$(( ${#idx} + 1 )) ;;
            *) _INDEX=0;  return 1 ;;
       esac
    }
    
    index(){
        _index "$@" && printf "%d
    " "$_INDEX"
    }

    例:基于月份的前3个字母,打印出对应的数值

    _month2num(){
        local month=JAN.FEB.MAR.APR.MAY.JUN.JUL.AUG.SEP.OCT.NOV.DEC
        _upword "${1:0:3}" ## 提取$1中的前3个字母,并转换为大写
        _index "$month" "$_UPWORD" || return 1
        _MONTH2NUM=$(( $_INDEX / 4 + 1 ))
    }
    
    month2num(){
        _month2num "$@" && printf "%s
    " "$_MONTH2NUM"
    }
  • 相关阅读:
    Angular入门到精通系列教程(3)
    Angular入门到精通系列教程(1)
    Angular入门到精通系列教程(2)
    嵌入在iframe中的Angular站点,如何打开一个新的tab页面
    简单实现无服务器情况下,2个GIT客户端的同步
    QP01 创建检验批计划
    IW31创建维修工单
    屏幕里输入字段值后的检查 SCREEN FIELD CHECK ON INPUT
    elasticsearch 基于文章点赞数计算评分
    script_score(帖子--根据 销量和浏览人数进行相关度提升)
  • 原文地址:https://www.cnblogs.com/mengrennwpu/p/10367454.html
Copyright © 2011-2022 走看看