1

I have a file with different columns (three in this simplified example). The rows contain data of different replicates (Replicate_A, Replicate_B, Replicate_C). However, there is not the same amount of rows per replicate (It can be 3, 4, 5 rows for example). The only thing I know is that each replicate starts with the number 1. I would like to add an extra column with the Replicate name. Any suggestion of how to add that column? I could create an extra file with the list of names to add in this extra column. Any suggestion is helpful.

The file I have is a tab delimited file.

1 x x  
2 x x  
3 x x  
4 x x  
1 x x  
2 x x  
3 x x  
1 x x  
2 x x  
3 x x

The file I want to have

1 x x Replicate_A
2 x x Replicate_A
3 x x Replicate_A
4 x x Replicate_A
1 x x Replicate_B
2 x x Replicate_B
3 x x Replicate_B
1 x x Replicate_C
2 x x Replicate_C
3 x x Replicate_C
  • Please edit your question and add more details: Do you want to specify all values (Replicate_A, Replicate_B, Replicate_C, etc.) for the additional column? Or should the script start with Replicate_A and automatically increment the last character? What should happen after Replicate_Z? Or are you sure that there will never be more than 26 replicates? – Bodo Sep 20 '19 at 8:50
  • Would you be OK with Replicate_1, Replicate_2 etc., instead of A, B, C? – terdon Sep 20 '19 at 8:58
  • Yes, actually the replicates are with numbers, Replicate -01, Replicate -02, until 10 – Andrea Cabrera Sep 20 '19 at 10:23
1

If you'd be OK using numbers instead of letters, you can do this very easily in awk (file has the output of running sed -i 's/ */\t/g' on your example data, to replace all consecutive spaces with tabs since you said your data are tab separated):

$ awk -F"\t" -vOFS="\t" '{if($1==1){num++}{print $0,"Replicate_"num}}' file 
1   x   x       Replicate_1
2   x   x       Replicate_1
3   x   x       Replicate_1
4   x   x       Replicate_1
1   x   x       Replicate_2
2   x   x       Replicate_2
3   x   x       Replicate_2
1   x   x       Replicate_3
2   x   x       Replicate_3
3   x   x   Replicate_3

If you need letters, it's a little more complex, but not too bad:

$ awk '{
        if(NR==FNR){
            a[++n]=$1
        }
        else{
            if($1==1){
                num++
            }
            print $0,"Replicate_"a[num]
        }
       }' <(printf '%s\n' {A..Z}) file
1   x   x    Replicate_A
2   x   x    Replicate_A
3   x   x    Replicate_A
4   x   x    Replicate_A
1   x   x    Replicate_B
2   x   x    Replicate_B
3   x   x    Replicate_B
1   x   x    Replicate_C
2   x   x    Replicate_C
3   x   x Replicate_C
  • Awesome!! Thank you so much it works perfect! – Andrea Cabrera Sep 20 '19 at 10:36
  • @AndreaCabrera glad I could help :) By the way, you might be interested in our sister site: Bioinformatics. – terdon Sep 20 '19 at 10:39
2

Using AWK, with a separate file listing the names to add:

#!/usr/bin/awk -f

BEGIN { FS = "\t"; OFS = FS; idx = 0 }
FNR == NR { names[NR] = $0 }
FNR < NR && $1 == 1 { idx++ }
FNR < NR { $(NF + 1) = names[idx]; print }

This sets AWK up to use tabs as field delimiters for input and output. The first file is assumed to contain the names to add; this is read into the names array. Once we move to files after the first, we add the current name to the end of the line, after checking if the first field is 1 and incrementing the array index if so.

Without a separate list of names:

#!/usr/bin/awk -f

BEGIN { FS = "\t"; OFS = FS; idx = 0 }
$1 == 1 { idx++ }
{ $(NF + 1) = sprintf("Replicate_%c", 64 + idx); print }

In both cases, there’s no error handling. In the first variant, once you run out of names, the empty string will be used instead. In the second, you’ll explore the character set after Z...

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.