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

时间:2019-01-25 14:34:27

标签: bash perl awk sed

我有一个看起来像这样的字符串 /foo/bar/baz59_ 5stuff.thing

如果最后一个数字大于另一个变量,我想将最后一个数字(示例中为5)增加一个。 9将增加到10。请注意,最后一个数字也可以是多个数字。 “ stuff.thing”也可以是任何东西;除数字外;因此无法对其进行硬编码。

上面的示例将导致/foo/bar/baz59_ 6stuff.thing

我发现了多个问题(和答案),这些问题将从字符串中提取出最后一个数字,并且显然可以将其用于比较。  我遇到的问题是如何确保当我进行替换时,我仅替换了最后一个数字(因为显然我不能仅将“ 5”替换为“ 6”)。有人可以提出任何建议吗?

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

7 个答案:

答案 0 :(得分:7)

更新后的答案

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

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

原始答案

您可以在Perl正则表达式中使用/e评估/计算替换项。在这里,我只将1添加到捕获的数字串中,但是您可以做更复杂的事情:

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

{希望(?!.*\d+)是负数,表示没有更多数字。

$1代表捕获组(\d+)中捕获的任何数字序列。

请注意,这需要进行修改以处理十进制数字,负数和科学计数法-但这是可能的。

答案 1 :(得分:4)

使用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

答案 2 :(得分:4)

使用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

答案 3 :(得分:1)

  

如果它大于脚本参数。

如果我正确理解了它(我假设您正在通过脚本传递参数,并且其值大于字符串的第二个字段数字,然后将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

答案 4 :(得分:1)

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

答案 5 :(得分:1)

这是一种较短的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 :(得分:0)

如果“测试”编号在“绑定”变量中:

perl -pe 'BEGIN{$bound=6} s{(\d+)_(\d+)(?!.*\d+)}{ $i=$2+1;($i>$bound? $1+1:$1)."_".$i}e' <<<"/foo/bar/baz59_5stuff.thing"
/foo/bar/baz59_6stuff.thing