如何替换文件名中的数字但从中减去1?

时间:2015-07-21 11:37:27

标签: regex linux sed

我在目录(linux)中有很多文件。

示例:

   .0130.  .0230. .0330. .0430.   ....2330.. ..2430. 

这里0930代表小时并且从1改为24(30不改变),日期也会改变。小时代表

  .0030.  .0130. .0230. .0330.   .... .2230. 

我想在文件名中替换此部分(仅此部分),减去1小时

   so  .0130. becomes .0030. 
       .0230. becomes .0130.

并且不要触摸文件名中的任何其他数字。

        2430. becomes .2330.

..............等等

 rename -n 's/(\d+)(\.vgf.img)/($1-1).$2/e' file300.data.20141231.MC.0930.vgf.img

我试过了:

       file300.data.20141231.MC.929.vgf.img

但是回复了这个:

.0930.

所以.929.成了.0830.,这不是我想要的。我寻找:{{1}}

3 个答案:

答案 0 :(得分:3)

正则表达式对于这样的任务并不是很好,并且使用awk或perl脚本会更容易。但是,如果你真的想要,你仍然可以在sed中完成它! =)

在sed中没有减少数字的简单方法,但你可以模仿它:

#!/bin/sed -f
# Replace number XX from line
# "/data/2014/file300.data.20141231.MC.XX30.vgf.img"
# with decremented number (XX-1)
# zero is not changed

# copy filename to hold space
h
# remove everything that is not a number
s/.*MC\.//
s/30\.vgf.*//
# ensure that we don't have leading zeroes
s/^0*//

# here all the magic begins, decrementing

# we need to move all trailing zeroes to begin of number
# we do it using cycle:

# clear test condition
t b
: b
# if we have zero - move it
/0$/{
  # remove from end
  s/0$//
  # append to begin
  s/^/0/
}
# if substitution was made - continue cycle
t b

# now we have nonzero at the end, decrement it
s/1$/0/
s/2$/1/
s/3$/2/
s/4$/3/
s/5$/4/
s/6$/5/
s/7$/6/
s/8$/7/
s/9$/8/

# here we change number of digits in our number, this needs to be done only 
# when number was of type 10*, in that case after all our permutations it is 
# represented as line of all zeroes - just remove one.
/^0*$/s/0//

# another cycle to put zeroes back at end
t e
: e
/^0/{
  # remove from beginning
  s/^0//
  # add to end, as 9
  s/$/9/
}
t e
# Now we have decremented number in pattern space and original filename in hold
# format number as two-digit:
s/^$/00/
s/^.$/0&/
# append it to hold space
H
# switch hold and pattern 
x
# now we manipulate string like "$filename\nXX" where XX is our decremented
# number.
# Replace number in filename with decremented one
s/\(.*MC\.\)..\(30.*\).\(..\)/\1\3\2/

答案 1 :(得分:1)

我最初把它写成一个有点诙谐的回答并且不打算发布,但看到Yury的解决方案(这很棒!)我觉得有必要将其作为至少可能有用的。

您没有充分指定问题,但假设您的文件都有结尾“$ {timestamp} .vgf.img”(实际上,假设时间戳后名称中存在两个点): / p>

 echo /data/2014/file300.data.20141231.MC.0930.vgf.img |
      awk '{a=substr($(NF-2),0,2); $(NF-2)=(a-1)"30"} 1' FS=. OFS=.

答案 2 :(得分:0)

您需要减去100而不是1,才能从930中得到830。然后,可以使用sprintf来格式化带前导零的结果。以下命令将按预期运行

~$ rename -n 's/(\d+)(\.vgf.img)/(sprintf("%04d", ($1 - 100))).$2/e' file300.data.20141231.MC.0930.vgf.img
rename(file300.data.20141231.MC.0930.vgf.img, file300.data.20141231.MC.0830.vgf.img)