sed 的 while 循环出错

sed 的 while 循环出错

我有一个要解析的文件:

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

所需的输出:

对于第一行

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

等等...

我只需要替换/mmu-miR创建一个新行以及第二列。

我尝试在 bash 上使用以下一行代码:

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

mmu-miR-15-5p
mmu-miR16-5p
mmu-miR195-5p
mmu-miR424-5p
mmu-miR497-5p   0610007P14Rik
mmu-miR-326-3p
mmu-miR330-5p   0610007P14Rik
mmu-miR-326-3p
mmu-miR330-5p   Lmir

我尝试使用while循环和这个 sed 命令:

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

但出现错误:

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

我究竟做错了什么?

答案1

如何实现这一目标awk

为了更好的可读性/易用性,请创建一个包含以下内容的awk脚本 ( myScript.awk):

{ 
  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"
    }    
  }
}

怎么运行的:

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

这条线取第一个场地(例如"mmu-miR-15-5p/16-5p/195-5p/424-5p/497-5p"第一行),用分隔符“/”将其分割,将其存储在数组中a,并将分割的元素数量存储在 中n。对于第一行:

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

请记住,awk每行都会执行指令,因此下一行的结果会有所不同!

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

类似地,该行获取第一个元素a并用分隔符“-”将其分隔。这产生:

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

一旦我们有了这些数组,我们需要做的就是循环输出行的数量(输入行中“/”分隔元素的数量)并用数组位ab!构造每行。我们必须对第一行破例,因为a[1]已经包含“mmu-miR-”,因此if要区分这种情况!

如何运行它

awk -f myScript.awk input.txt

测试了一下,它确实输出了您在问题中所要求的内容。

笔记 正如我在对您的问题的评论中所述,使用单次awk调用比在文件的每一行上循环更有效且“shell 友好”。

编辑注释 我根据您的评论修改了脚本。现在应该好了!

答案2

我想你正在寻找类似的东西:

cat inputFile.txt | while read line
    do
        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')
        do
            echo "$realname-$port $tag"
            #or echo "$realname$port $tag", but I suspect a typo in your initial post
        done
    done

答案3

假设输入是无标头 TSV 文件(即没有标头行的制表符分隔文件),那么您可以使用以下命令读取它:磨坊主( mlr) 和“取消嵌套”每个记录由/第一个字段中的 - 分隔字符串组成。然后,您可以将该字符串添加到mmu-miR-第一个字段中尚未包含该字符串的每个值中:

$ mlr --tsv -N nest --evar '/' -f 1 then put -S '$1 !=~ "^mmu-miR-" { $1 = "mmu-miR-" . $1 }' file
mmu-miR-15-5p   0610007P14Rik
mmu-miR-16-5p   0610007P14Rik
mmu-miR-195-5p  0610007P14Rik
mmu-miR-424-5p  0610007P14Rik
mmu-miR-497-5p  0610007P14Rik
mmu-miR-326-3p  0610007P14Rik
mmu-miR-330-5p  0610007P14Rik
mmu-miR-326-3p  Lmir
mmu-miR-330-5p  Lmir
mmu-miR-15      0610007P14Rik
mmu-miR-16      0610007P14Rik
mmu-miR-195     0610007P14Rik
mmu-miR-424     0610007P14Rik
mmu-miR-497     0610007P14Rik
mmu-miR-15-5p   0610007P14Rik
mmu-miR-16-5p   0610007P14Rik
mmu-miR-195-5p  0610007P14Rik
mmu-miR-424-5p  0610007P14Rik
mmu-miR-497-5p  0610007P14Rik
mmu-miR-6838-5p 0610007P14Rik
mmu-miR-15      Alinf
mmu-miR-16      Alinf
mmu-miR-195     Alinf
mmu-miR-424-5p  Alinf
mmu-miR-497     Alinf
mmu-miR-326     0610007P14Rik
mmu-miR-330-5p  0610007P14Rik
mmu-miR-326     0610007P14Rik
mmu-miR-330     0610007P14Rik
mmu-miR-1       Crgi
mmu-miR-206     Crgi
mmu-miR-613     Crgi
mmu-miR-1-3p    0610007P14Rik
mmu-miR-206     0610007P14Rik

第一个 Miller 子命令nest在这里用于通过将斜杠上的第一个字段拆分并复制其他字段(在本例中只有一个其他字段)一次,将记录“取消嵌套”或“分解”为更多记录每个生成的字符串。

第二个 Miller 子命令put测试结果第一个字段中的值是否以正确的前缀字符串开头,如果不是则添加它。选项-S阻止put米勒推断字段上的类型并将所有字段视为文本


给定问题中的输入,我们可能会得到相同的结果,awk如下所示:

awk -F '\t' '
    BEGIN { OFS=FS }
    {
        nf = split($1,a,"/")
        
        print a[1], $2
        for (i = 2; i <= nf; ++i)
            print "mmu-miR-" a[i], $2
    }' file

这还将文件作为制表符分隔的文件读取,并用斜杠分割第一个字段,在数组中生成一组新字符串a。然后,它会打印第一个生成的字符串和第二个字段,然后迭代其余生成的字符串,在每个字符串前面添加缺少的mmu-miR-前缀,并使用第二个字段中的值输出它们。

相关内容