I have a file I want to parse:

mmu-miR-15-5p/16-5p/195-5p/424-5p/497-5p    0610007P14Rik
mmu-miR-326-3p/330-5p   0610007P14Rik
mmu-miR-326-3p/330-5p   Lmir
mmu-miR-15/16/195/424/497   0610007P14Rik
mmu-miR-15-5p/16-5p/195-5p/424-5p/497-5p/6838-5p    0610007P14Rik
mmu-miR-15/16/195/424-5p/497    Alinf
mmu-miR-326/330-5p  0610007P14Rik
mmu-miR-326/330 0610007P14Rik
mmu-miR-1/206/613   Crgi
mmu-miR-1-3p/206    0610007P14Rik

the desired output:

for the first line

mmu-miR-15-5p   0610007P14Rik
mmu-miR16-5p    0610007P14Rik
mmu-miR195-5p   0610007P14Rik
mmu-miR424-5p   0610007P14Rik
mmu-miR497-5p   0610007P14Rik

and so on...

I just need to replace / with mmu-miR and create a new line along with their second column.

I tried with following one line code on bash:

sed 's/\//\nmmu-miR/g' test.txt

mmu-miR497-5p   0610007P14Rik
mmu-miR330-5p   0610007P14Rik
mmu-miR330-5p   Lmir

I tried to use a while loop and this sed command:

while read line; do 
    lineCols=( $line ); 
    v1=($(echo "${lineCols[0]}"));
    v2=($(echo "${lineCols[1]}"));
    sed 's/\//\n/g' ${v1};
done <test.txt

but got an error:

sed: can't read mmu-miR-15-5p/16-5p/195-5p/424-5p/497-5p: No such file or directory
sed: can't read mmu-miR-326-3p/330-5p: No such file or directory
sed: can't read mmu-miR-326-3p/330-5p: No such file or directory
sed: can't read mmu-miR-15/16/195/424/497: No such file or directory
sed: can't read mmu-miR-15-5p/16-5p/195-5p/424-5p/497-5p/6838-5p: No such file or directory

What am I doing wrong?

  • 1
    You should avoid while read line; echo ... constructs (see here for further details). Furthermore, this looks like a job more suited for awk than sed, but that might be a pretty subjective matter. Nov 14, 2016 at 17:38

2 Answers 2


How to achieve this with awk

For better readability/ease of use, create a awk script (myScript.awk) with following content:

  n=split($1, a, "/")
  split(a[1], b, "-")

  for (i=1; i<n+1; i++) {
    if (i == 1) {
      printf a[i]"\t"$2"\n"
    else {
      printf b[1]"-"b[2]"-"a[i]"\t"$2"\n"

How it works:

n=split($1, a, "/")

This line takes the first field (for example "mmu-miR-15-5p/16-5p/195-5p/424-5p/497-5p" for the first line), splits it with separator "/", stores it in array a and stores the number of elements split in n. For the first line:

a[1] = "mmu-miR-15-5p"
a[2] = "16-5p"
a[3] = "195-5p"
a[4] = "424-5p"
a[5] = "497-5p"
n = 5

Remember awk instructions are executed for every line so the result will be different for the next line !

split(a[1], b, "-")

Similarly, this line takes the first element of a and splits it with separator "-". This yields:

b[1] = "mmu"
b[2] = "miR"
b[3] = "15"
b[4] = "5p"

Once we have those arrays, all we need to do is loop over the number of output lines (number of "/" separated elements in an input line) and construct each line with bits of arrays a and b! We have to make an exception for the first line because a[1] already contains "mmu-miR-" hence the if to differentiate that case !

How to run it

awk -f myScript.awk input.txt

Tested it, it does output what you ask for in your question.

NOTE As stated in my comment on your question, using a single awk invocation is way more efficient and "shell-friendly" than looping on every line of your file.

EDIT NOTE I have modified the script following your comment. Should be fine now !


I think you're looking for something like that:

cat inputFile.txt | while read line
        eval `echo "$line" | sed 's|^\([^/]*\)/\([^ ]*\) \(.*\)|name="\1" ports=\2 tag="\3"|'`
        echo "$name $tag"
        realname=`echo "$name" | sed 's|-[0-9].*||'`
        for port in $(echo $ports | sed 's|/| |g')
            echo "$realname-$port $tag"
            #or echo "$realname$port $tag", but I suspect a typo in your initial post

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.