代码之家  ›  专栏  ›  技术社区  ›  UKMonkey

如何增加字符串中的最后一个数字;bash

  •  7
  • UKMonkey  · 技术社区  · 7 年前

    我有根绳子看起来像 /foo/bar/baz59_ 5stuff.thing

    如果最后一个数字大于另一个变量,我想把它(示例中的5)增加一个。9将增加到10。请注意,最后一个数字也可以是多个数字,“stufacture.thing”可以是除数字之外的任何数字,因此不能硬编码。

    上面的例子会导致 /foo/bar/baz59_ 6stuff.thing

    我发现了多个问题(和答案),可以从字符串中提取最后一个数字,很明显,可以在比较中使用。 我面临的问题是如何确保当我进行替换时,我只替换最后一个数字(显然我不能只替换“5”代表“6”)。有人能提出建议吗?

    awk/sed/bash/grep都是可行的。

    6 回复  |  直到 7 年前
        1
  •  7
  •   Mark Setchell    7 年前

    更新答案

    感谢@edmorton指出数字超过阈值的进一步要求。可以这样做:

    perl -spe 's/(\d+)(?!.*\d+)/$1>$thresh? $1+1 : $1/e' <<<  "abc123_456.txt" -- -thresh=500
    

    原始答案

    您可以使用 /e 在Perl正则表达式中。在这里,我只需在捕获的数字串中添加1,但您可以执行更复杂的操作:

    perl -pe 's/(\d+)(?!.*\d+)/$1+1/e' <<< "abc123_456.txt"
    abc123_457.txt
    

    这个 (?!.*\d+) 是(希望)对更多数字的负面展望。

    这个 $1 表示捕获组中捕获的任何数字序列 (\d+) .

    请注意,这需要修改以处理十进制数、负数和科学记数法——但这是可能的。

        2
  •  4
  •   glenn jackman    7 年前

    使用bash正则表达式匹配:

    $ f="/foo/bar/baz59_ 99stuff.thing"
    $ [[ $f =~ ([0-9]+)([^0-9]+)$ ]]
    

    好的,我们现在有什么?

    $ declare -p BASH_REMATCH
    declare -ar BASH_REMATCH=([0]="99stuff.thing" [1]="99" [2]="stuff.thing")
    

    所以我们可以构建新的文件名

    if [[ $f =~ ([0-9]+)([^0-9]+)$ ]]; then
        prefix=${f%${BASH_REMATCH[0]}}           # remove "99stuff.thing" from $f
        number=$(( 10#${BASH_REMATCH[1]} + 1 ))  # use "10#" to force base10
        new=${prefix}${number}${BASH_REMATCH[2]}
        echo $new
    fi
    # => /foo/bar/baz59_ 100stuff.thing
    
        3
  •  4
  •   Ed Morton    7 年前

    对于第3个arg to match()的gnu awk:

    $ awk -v t=3 'match($0,/(.*)([0-9]+)([^0-9]*)$/,a) && a[2]>t{a[2]++; $0=a[1] a[2] a[3]} 1' file
    /foo/bar/baz59_ 6stuff.thing
    

    刚设定 t 无论您的门限值是多少,例如:

    $ awk -v t=7 'match($0,/(.*)([0-9]+)([^0-9]*)$/,a) && a[2]>t{a[2]++; $0=a[1] a[2] a[3]} 1' file
    /foo/bar/baz59_ 5stuff.thing
    
        4
  •  1
  •   RavinderSingh13 Nikita Bakshi    7 年前

    如果它大于脚本参数。

    如果我得到了正确的结果(我假设你正在通过一个脚本传递一个参数,如果它的值大于字符串的第二个字段数字,那么在第二个字段的数字中增加1),你能试试下面的方法吗?

    cat script.ksh
    value=$1
    echo "/foo/bar/baz59_ 5stuff.thing" | 
    awk -v arg="$value" '
      match($2,/[0-9]+/){
        val=substr($2,RSTART,RLENGTH)
        val=val<arg?val+1:val
        $2=val substr($2,RSTART+RLENGTH)
    }
    1'
    

    下面是我运行script.ksh时的一个示例,它给出了以下输出。

    /script.ksh 7
    /foo/bar/baz59_ 6stuff.thing
    
        5
  •  1
  •   anubhava    7 年前

    这是一个短点的 gnu awk 途径:

    cat incr.awk
    {
       n = split($0, a, /[0-9]+/, b)
       for(i=1; i<n; i++)
          s = s a[i] b[i] + (b[i] < max && i == n-1 ? 1 : 0)
       print s a[i]
    }
    

    然后使用它作为:

    awk -v max=80 -f incr.awk <<< '/foo/bar/baz59_ 5stuff.thing'
    /foo/bar/baz59_ 6stuff.thing
    
    awk -v max=80 -f incr.awk <<< '/foo/bar/baz59_ 79stuff.thing'
    /foo/bar/baz59_ 80stuff.thing
    
    
    awk -v max=80 -f incr.awk <<< '/foo/bar/baz59_ 90stuff.thing'
    /foo/bar/baz59_ 90stuff.thing
    
    awk -v max=80 -f incr.awk <<< '/foo/bar/baz59_ 80stuff.thing'
    /foo/bar/baz59_ 80stuff.thing
    
    awk -v max=80 -f incr.awk <<< '/foo/bar/stuff.thing'
    /foo/bar/stuff.thing
    
        6
  •  1
  •   James Brown    7 年前

    AWK:

    $ echo /foo/bar/baz59_ 99stuff.thing |
    awk '
    /[0-9]/ {
        rstart=1                                    # keep track of the start
        while(match(substr($0,rstart),/[0-9]+/)) {  # while numbers last
            rstart+=RSTART+RLENGTH-1                # increase rstart
            rlength=RLENGTH                         # remember length too
        }
        v=substr($0,rstart-rlength,rlength)+1                    # increase last number
        print substr($0,1,rstart-rlength-1) v substr($0,rstart)  # print in parts
        next
    }1'                                             # in case there was no number
    /foo/bar/baz59_ 100stuff.thing
    

    编辑 :

    哎呀,我错过了辩论的要求( 如果最后一个数字大于脚本参数,则增加一个。 ):

    $ echo /foo/bar/baz59_ 99stuff.thing |
    awk -v arg=100 '
    /[0-9]/ {
        rstart=1
        while(match(substr($0,rstart),/[0-9]+/)) {
            rstart+=RSTART+RLENGTH-1
            rlength=RLENGTH
        }
        v=substr($0,rstart-rlength,rlength)
        if(0+v>arg) {                           # test if v greater that argument
            print substr($0,1,rstart-rlength-1) v+1 substr($0,rstart)
            next
        }
    }1'
    

    现在输出:

    /foo/bar/baz59_ 99stuff.thing