我有一个要解析的文件:
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"
一旦我们有了这些数组,我们需要做的就是循环输出行的数量(输入行中“/”分隔元素的数量)并用数组位a
和b
!构造每行。我们必须对第一行破例,因为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-
前缀,并使用第二个字段中的值输出它们。