Database 如何使用sed在使用引用文件的文件中进行数千次替换?

Database 如何使用sed在使用引用文件的文件中进行数千次替换?,database,bash,dictionary,awk,sed,Database,Bash,Dictionary,Awk,Sed,我有一个大文件,有两列,如下所示: tiago@tiago:~/$ head Ids.txt TRINITY_DN126999_c0_g1_i1 ENSMUST00000040656.6 TRINITY_DN126999_c0_g1_i1 ENSMUST00000040656.6 TRINITY_DN126906_c0_g1_i1 ENSMUST00000126770.1 TRINITY_DN126907_c0_g1_i1 ENSMUST00000192613.1 TRINITY_

我有一个大文件,有两列,如下所示:

 tiago@tiago:~/$ head Ids.txt 
 TRINITY_DN126999_c0_g1_i1 ENSMUST00000040656.6
 TRINITY_DN126999_c0_g1_i1 ENSMUST00000040656.6
 TRINITY_DN126906_c0_g1_i1 ENSMUST00000126770.1
 TRINITY_DN126907_c0_g1_i1 ENSMUST00000192613.1
 TRINITY_DN126988_c0_g1_i1 ENSMUST00000032372.6
 .....
"baseMean" "log2FoldChange" "lfcSE" "stat" "pvalue" "padj" "super" "sub" "threshold"
"TRINITY_DN41319_c0_g1" 178.721774751278 2.1974294626636 0.342621318593487 6.41358066008381 1.4214085388179e-10 5.54686423073089e-08 TRUE FALSE "TRUE"
"TRINITY_DN87368_c0_g1" 4172.76139849472 2.45766387851112 0.404014016558211 6.08311538160958 1.17869459181235e-09 4.02673069375893e-07 TRUE FALSE "TRUE"
"TRINITY_DN34622_c0_g1" 39.1949851245197 3.28758092748061 0.54255370348027 6.05945716781964 1.3658169042862e-09 4.62597265729593e-07 TRUE FALSE "TRUE"
.....
我还有另一个包含数据的文件,如下所示:

 tiago@tiago:~/$ head Ids.txt 
 TRINITY_DN126999_c0_g1_i1 ENSMUST00000040656.6
 TRINITY_DN126999_c0_g1_i1 ENSMUST00000040656.6
 TRINITY_DN126906_c0_g1_i1 ENSMUST00000126770.1
 TRINITY_DN126907_c0_g1_i1 ENSMUST00000192613.1
 TRINITY_DN126988_c0_g1_i1 ENSMUST00000032372.6
 .....
"baseMean" "log2FoldChange" "lfcSE" "stat" "pvalue" "padj" "super" "sub" "threshold"
"TRINITY_DN41319_c0_g1" 178.721774751278 2.1974294626636 0.342621318593487 6.41358066008381 1.4214085388179e-10 5.54686423073089e-08 TRUE FALSE "TRUE"
"TRINITY_DN87368_c0_g1" 4172.76139849472 2.45766387851112 0.404014016558211 6.08311538160958 1.17869459181235e-09 4.02673069375893e-07 TRUE FALSE "TRUE"
"TRINITY_DN34622_c0_g1" 39.1949851245197 3.28758092748061 0.54255370348027 6.05945716781964 1.3658169042862e-09 4.62597265729593e-07 TRUE FALSE "TRUE"
.....
我正在考虑使用sed来翻译数据文件第一列中的值,将第一个文件用作字典

也就是说,依次考虑数据文件的每一行,如果第一列中的值与字典文件的第一列中的值匹配,则将进行替换;否则,该行将被简单地打印出来


任何建议都将不胜感激。

您可以将第一个文件
Ids.txt
转换为sed脚本:

$ sed -r 's| *(\S+) (\S+)|s/^"\1/"\2/|' Ids.txt > repl.sed
$ cat repl.sed
s/^"TRINITY_DN126999_c0_g1_i1/"ENSMUST00000040656.6/
s/^"TRINITY_DN126999_c0_g1_i1/"ENSMUST00000040656.6/
s/^"TRINITY_DN126906_c0_g1_i1/"ENSMUST00000126770.1/
s/^"TRINITY_DN126907_c0_g1_i1/"ENSMUST00000192613.1/
s/^"TRINITY_DN126988_c0_g1_i1/"ENSMUST00000032372.6/
这将删除前导空格,并使每一行成为替换命令

然后,您可以使用此脚本在数据文件中进行替换:

sed -f repl.sed datafile
。。。重定向到另一个文件,或使用
sed-i
就地执行

如果没有使用GNU,可以使用符合POSIX的第一个命令版本:

sed 's| *\([^ ]*\) \([^ ]*\)|s/^"\1/"\2/|' Ids.txt
这使用基本而不是扩展正则表达式,并使用
[^]
表示“非空格”,而不是
\S

,因为第一个文件(字典文件)很大,所以使用
sed
可能非常慢;一种更快且不太复杂的方法是使用
awk
,如下所示:

#!/bin/bash

# Declare hash table
declare -A Ids

# Go though first input file and add key-value pairs to hash table
while read Id; do
    key=$(echo $Id | cut -d " " -f1)
    value=$(echo $Id | cut -d " " -f2)
    Ids+=([$key]=$value)
done < $1

# Go through second input file and replace every first column with
# the corresponding value in the hash table if it exists
while read line; do
    first_col=$(echo $line | cut -d '"' -f2)
    new_id=${Ids[$first_col]}

    if [ -n "$new_id" ]; then
        sed -i s/$first_col/$new_id/g $2
    fi
done < $2
awk -v col=1 -v dict=Ids.txt '
  BEGIN {while(getline<dict){a["\""$1"\""]="\""$2"\""} } 
  $col in a {$col=a[$col]}; {print}'
awk-v col=1-v dict=Ids.txt'

BEGIN{while(GetLine)如果数据文件包含Ids.txt中不存在的密钥怎么办?根据问题描述,它应该保持不变。如果repl.sed中的行如下所示,则效率更高,可能更安全:s/^“…/”…使用parallel运行所有6个文件需要15分钟才能完成对每行输入运行一次
cut
和两次
sed
与运行两次
sed
相比,速度会非常慢,一次创建
sed
脚本,然后一次运行
sed
脚本。如果只有两个li如果要更改,这没什么大不了的,但是有成千上万个。好吧,这取决于sed脚本是否能够一次编辑文件,我不认为是这样(?)。如果每行
s/xxx/yyy/
都会导致
sed
遍历数据文件,那么每个id只需一次。我编辑了我的代码,在获取
第一列时删除了一个不必要的
sed
,但当然它仍然会在每次迭代中执行
sed
cut
一次。
sed
是a(the?)“流编辑器”。它将脚本中的操作依次应用于每一行输入。它可以处理任意大的数据文件;
sed
的旧版本可能会遇到足够大的
sed
脚本的问题,但大多数现代版本的
sed
已经失去了旧版本的限制。好的,我做了计算。给定n=(数据文件中的行),m=(ID文件中的行),sed脚本逐行遍历数据文件,每个
s/xxx/yyy/
应用一次,因此复杂度为n×m。我的脚本遍历数据文件一次,但对数据文件再次进行替换,因此复杂度为n×n。给定n>>m,我的脚本的计算复杂度较低,但如果≈ n或甚至m>n如果
cut
需要很长时间,那么我的脚本应该会慢一些。在每次迭代中重新启动
sed
都会受到一些惩罚。我认为真正的惩罚是Bash循环速度太慢。事实上,它比sed快得多。@TiagoBruno-你能更具体一点吗?实际上,这会很有趣g(可能对某些人有用)为(a)awk解决方案;(b)发布的sed解决方案;(c)修改后的sed解决方案使用
s/^../…/
而不仅仅是
s/”…/…/
。我将很快在这里发布每个解决方案所用的时间。在一些虚拟文件上进行的测试表明,awk的加速系数为2-3,但正如您所说,使用大型字典文件,这可能会更大。期待对真实数据的测量!