我有一个对象列表,这些对象的名称具有相同的格式(*_region_NNN
其中*
代表变量名称并且NNN
是数字)。我需要以相同的顺序获取相同的列表,但使用序号修改名称的数字部分。对象按字母顺序排序。所有同名对象 ( *
) 必须从 001 开始按顺序编号
列表.txt:
BIRC2_region_087
BIRC2_region_089
BIRC2_region_114
BMI1_region_193
BMI1_region_243
CRBN_region_109
CRBN_region_134
CRBN_region_145
CDC20_region_001
CDC20_region_002
CDC20_region_004
CBL_region_002
CBL_region_003
CBL_region_004
CBL_region_005
CBL_region_006
CBL_region_008
CBL_region_009
CBL_region_024
CBL_region_033
CBL_region_042
CBL_region_048
CBL_region_075
CBL_region_076
CBL_region_086
CBL_region_111
CBL_region_112
CBL_region_146
CBL_region_172
CBL_region_248
CBL_region_252
输出.txt
BIRC2_region_001
BIRC2_region_002
BIRC2_region_003
BMI1_region_001
BMI1_region_002
CRBN_region_001
CRBN_region_002
CRBN_region_003
CDC20_region_001
CDC20_region_002
CDC20_region_003
CBL_region_001
CBL_region_002
CBL_region_003
CBL_region_004
CBL_region_005
CBL_region_006
CBL_region_007
CBL_region_008
CBL_region_009
CBL_region_010
CBL_region_011
CBL_region_012
CBL_region_013
CBL_region_014
CBL_region_015
CBL_region_016
CBL_region_017
CBL_region_018
CBL_region_019
CBL_region_020
有人可以帮我吗?
答案1
使用awk
它不需要将全部/部分输入数据缓冲到内存中(因为您提到的数据已经排序):
awk -F'_[^_]*$' 'pre!=$1{ id=0 }
{ pre=$1; printf("%s_%03d\n", $1, ++id) }' infile
我们_[^_]*$
最后定义的_<zero-or-more-of-any-characters-but-not-underscore><end-of-line>
作为字段分隔符。
[^_]
意味着任何单身的除下划线外的字符(也包括换行符); and[^_]*
表示<零个或多个任何字符但不下划线>,$
是<行尾>锚点。
如果剩余行的一部分(可通过 访问$1
)与前一行不同,则将 id 计数重置为 0,否则打印$1
并递增 id,并带有 3 个前导零。
动态补零控制:
<infile awk -F'_[^_]*$' '{ print $1 }' \
|sort |uniq -c |sort -r \
|awk 'NR==1{ z=length($1) } { for(i=1; i<=$1; i++) printf("%s_%0*d\n", $2, z, i) }'
答案2
awk -F"_" '{printf "%s_%s_%03d\n",$1,$2,++n[$1]}' infile.txt
解释:
-F"_"
:用作_
字段分隔符printf
:以定义的格式打印:%s
=字符串,_
=文字下划线,%03d
零填充的3位整数,\n
换行符++n[$1]
对字段 1(区域 ID)的出现进行计数并增加计数器,在使用该值之前执行该操作(否则从 0 开始)
答案3
与中相同的想法αГsнιn 的回答,但执行方式略有不同:
awk '
{ $0 = substr($0, 0, length - 4) }
$0 != prev { n = 0 }
{ printf "%s_%.3d\n", $0, ++n; prev = $0 }' file
第一个块删除行末尾现有的三位数以及前面的下划线,产生一种前缀字符串。
n
如果前一行与当前行(新的前缀字符串)不同,中间块将计数器重置为零。
最后一个块增加计数器并将其输出为前缀字符串末尾的一个由零填充的三位数整数,中间有一个下划线。最后,当前行被记住为prev
。