【问题标题】:extract a numeric substring and add value to it提取数字子字符串并向其添加值
【发布时间】:2017-05-15 05:00:28
【问题描述】:

我有一个类似1001.2001.3001.5001.60011001-2001-3001-5001-6001 的字符串。如何提取第 4 个字符串,即5001,添加一个类似121 的值并将其放回相同的字符串中。输出应该类似于1001.2001.3001.5122.60011001-2001-3001-5122-6001。我必须在 Linux bash 脚本中实现这一点。

【问题讨论】:

  • 你自己尝试了什么?
  • 你应该检查here
  • 这里的瓶颈是你有多个 delims。如果你有 GNU awk,这个[ answer ] 很好地指出了一个解决方法
  • 如果没有任何尝试,您似乎只是希望其他人为您完成工作。这一切都可以通过简单的 bash 替换来完成。

标签: bash shell


【解决方案1】:

试试这个

#!/bin/bash
str=$1 
if [[ $(echo $str | grep '\.'  | wc -l) == 1 ]]
then
   str1=$(echo $str |  cut -d '.' -f 1,2,3)
   str2=$(echo $str | cut -d '.' -f 4 | awk {'print $1+121'})
   str3=$(echo $str |  cut -d '.' -f 5)
   echo $str1.$str2.$str3

elif [[ $(echo $str | grep - | wc -l) == 1 ]]
then
    str1=$(echo $str |  cut -d '-' -f 1,2,3)
    str2=$(echo $str | cut -d '-' -f 4 | awk {'print $1+121'})
    str3=$(echo $str |  cut -d '-' -f 5) 
    echo $str1-$str2-$str3
else
    echo "do nothing"
fi

传递一个字符串作为参数

【讨论】:

    【解决方案2】:

    没有管道,没有叉子,没有切割,没有 awking,只有普通的 POSIX shell:

    $ s=1001.2001.3001.5001.6001
    $ oldIFS=$IFS
    $ IFS=.-
    $ set -- $s
    $ case $s in
    > (*.*) echo "$1.$2.$3.$(($4 + 121)).$5";;
    > (*-*) echo "$1-$2-$3-$(($4 + 121))-$5";;
    > esac
    1001.2001.3001.5122.6001
    $ IFS=$oldIFS
    

    【讨论】:

    • 为什么投反对票?如果有什么问题,请给我一个改进的机会。
    【解决方案3】:

    一个班轮

    value=121 ; str='1001.2001.3001.5001.6001' ; token="$(echo "$str" | cut -f 4 -d '.')" ; newtoken=$(( $token + $value )) ; newstr="$(echo "$str" | sed -e "s/$token/$newtoken/g" | tr '.' '-')" ; echo "$newstr"
    

    细分:

    value=121                                            # <- Increment
    str='1001.2001.3001.5001.6001'                       # <- Initial String
    token="$(echo "$str" | cut -f 4 -d '.')"             # <- Extract the 4th field with . sep
    newtoken=$(( $token + $value ))                      # <- Add value and save to $newtoken
    newstr="$(echo "$str" \
    | sed -e "s/$token/$newtoken/g" \
    | tr '.' '-')"                                       # <- Replace 4th field with $newtoken
                                                         #    and translate "." to "-"
    echo "$newstr"                                       # <- Echo new string
    

    工作于:

    • 重击
    • sh
    • FreeBSD
    • 忙箱

    使用开箱即用的工具

    【讨论】:

      【解决方案4】:

      如果字段分隔符可以是.-,则执行类似的操作

      echo "1001.2001.3001.5001.6001" | awk 'BEGIN{FS="[.-]";OFS="-"}{$4+=121}1'
      1001-2001-3001-5122-6001
      

      但是,如果您需要将正则表达式 FS 或字段分隔符与 OFS 匹配,那么您需要安装 gawk

      echo "1001.2001.3001.5001.6001" |
      gawk 'BEGIN{FS="[.-]"}{split($0,a,FS,seps)}{$4+=121;OFS=seps[1]}1'
      1001.2001.3001.5122.6001
      

      【讨论】:

      • @hmedia1 羞耻??你为什么不认为这是一个可能的解决方案?而且我什至没有声称这是最好的解决方案。
      【解决方案5】:

      尽管使用值重置参数列表可能是首选方式,或者通过将IFS 设置为 delimiter 并将值读入数组并将所需值添加到数组索引问题,您也可以通过一个简单的循环来查找 delimiters 并不断跳过字符,直到找到所需的段(在您的情况下为4 - 当分隔符计数为 3 )。然后只需在每个 数组索引 处添加数字,直到找到下一个分隔符,即可为您提供基值。只需将所需的121 添加到完整的号码即可完成脚本,例如

      #!/bin/bash
      
      str=${1:-"1001.2001.3001.5001.6001"}    ## string
      ele=${2:-4}     ## element to add value to [1, 2, 3, ...]
      add=${3:-121}   ## value to add to element
      cnt=0           ## flag to track delimiters found
      num=
      
      ## for each character in str
      for ((i = 0; i < ${#str}; i++))
      do
          if [ "${str:$i:1}" = '.' -o "${str:$i:1}" = '-' ]   ## is it '.' or '-'
          then
              (( cnt++ ))                 ## increment count
              (( cnt == ele )) && break   ## if equal to ele, break
      
          ## check each char is a valid digit 0-9
          elif [ "0" -le "${str:$i:1}" -a "${str:$4i:1}" -le "9" ]
          then
              (( cnt == (ele - 1) )) || continue  ## it not one of interest, continue
              num="$num${str:$i:1}"               ## append digit to num
          fi
      done
      
      ((num += add))  ## add the amount to num
      
      printf "num: %d\n" $num     ## print results
      

      使用/输出示例

      $ bash parsenum.sh
      num: 5122
      
      $ bash parsenum.sh "1001.2001.3001.5001.6001" 2
      num: 2122
      
      $ bash parsenum.sh "1001.2001.3001.5001.6001" 2 221
      num: 2222
      

      查看一下,如果您有任何问题,请告诉我。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2018-07-17
        • 2016-01-04
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2014-05-26
        • 1970-01-01
        相关资源
        最近更新 更多