-1

I have a list of objects and the name of these has the same format (*_region_NNN where * represent a variable name and NNN are number). I need to obtain the same list in the same order but modify the numerical part of the name using sequential number. Objects are sorted alphabetically. All objects of the same name (*) must be sequentially numbered starting from 001

list.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

ouput.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

Could someone help me please?

0
4
awk -F"_" '{printf "%s_%s_%03d\n",$1,$2,++n[$1]}' infile.txt

Explanation:

  • -F"_": use _ as field separator
  • printf: print with defined format: %s = string, _ = literal underscore, %03d zero-padded 3-digit integer, \n newline
  • ++n[$1] count and increase counter for appearances of field 1 (region ID), do the operation before using the value (otherwise starts at 0)
2
  • 3
    Note that this assumes that the highest number is 999. If the largest number can be greater, e.g. 1000, then the first will still be 001 and not 0001. No idea if this is a problem for the OP but might be worth mentioning. – terdon Mar 11 at 9:57
  • The memory consumption of this is proportional to the number of unique prefix strings (the bit before the first _). If these are gene names (they look like it), we can expect about 20000 such strings, which is about 100 kB for an average of five letters per gene name. Not much, but about 100 kB more than necessary :-) – Kusalananda Mar 13 at 16:00
5

Use awk that doesn't require buffering fully/partially input data into memory (as your data you mentioned already sorted):

awk -F'_[^_]*$' 'pre!=$1{ id=0 }
{ pre=$1; printf("%s_%03d\n", $1, ++id) }' infile

With _[^_]*$ we defined very last _<zero-or-more-of-any-characters-but-not-underscore><end-of-line> as field seperator.

[^_] means any single character except underscore (exceptionally newline character as well); and [^_]* means <zero-or-more-of-any-characters-but-not-underscore>, the $ is <end-of-line> anchor.

if part of remained line (which is accessible by $1) was differ from previous one, then reset the id count to 0, else print $1 and incremental ids with 3 leading zeros.


Dynamic zero padding control:

<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) }'
0

Same idea as in αғsнιη's answer, but executed slightly differently:

awk '
    { $0 = substr($0, 0, length - 4) }
    $0 != prev { n = 0 }
    { printf "%s_%.3d\n", $0, ++n; prev = $0 }' file

The first block removes the existing three-digit number at the end of the line, as well as the preceding underscore, yielding a sort of prefix string.

The middle block resets the counter n to zero if the previous line was not the same as the current line (a new prefix string).

The last block increments the counter and outputs it as a zero-filled three digit integer at the end of the prefix string, with an underscore in-between. Finally, the the current line is remembered as prev.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.