在sed中查找并替换文本文件中的多个字符串

时间:2015-03-12 16:42:37

标签: regex bash sed

下面是一个玩具文本文件,其中包含样本和特征信息以及测量值。

Sample3_trait1  8.5
Sample6_trait2 2.2
Sample7_trait1 9.2
Sample3_trait2 1.3
Sample6_trait1 10.0
Sample7_trait2 2.1

我想用更具信息性的内容替换样本列,例如样本的实际名称(比如人名)。如果只有3个样本,例如sed,这将相对容易。

sed  's/Sample3/john.D/g' file.txt

我可以为每个"样本"执行此操作。但我有100或数千个样本名称。

id喜欢做的是给sed一个包含两列的文本文件,原始文件和替换文字:

Sample3 john.D
Sample6 mary.D
Sample7 kelly.O
....
Sample1001 amy.P

让它们替换它们在整个文件中出现的位置(全局),即,无论找到Sample3,都用john.D替换。

这是我可以用Bash循环做的事情吗?我可以循环遍历单个列(逐行),但我不知道如何处理匹配的列。

非常感谢任何帮助。

2 个答案:

答案 0 :(得分:2)

在这里使用awk会更好:

awk -v OFS=_ 'NR==FNR{a[$1]=$2;next} $1 in a{$1=a[$1]} 1' names.txt FS=_ file.txt
john.D_trait1 8.5
mary.D_trait2 2.2
kelly.O_trait1 9.2
john.D_trait2 1.3
mary.D_trait1 10.0
kelly.O_trait2 2.1

names.txt是这样的:

Sample3 john.D
Sample6 mary.D
Sample7 kelly.O

答案 1 :(得分:1)

使用sed将第二个文件转换为编辑第一个文件的sed脚本:

sed 's/\([^ ]*\) \(.*\)/s%\1_%\2_%/' file.2 > sed.script
sed -f sed.script file.txt
rm -f sed.script

Bash代码中没有循环。注意模式中的_;这对于阻止Sample3Sample300映射到john.D00非常重要。

如果您应该如此担心脚本的中断和并发运行,那么(a)使用mktemp生成文件名来代替sed.script,以及(b)陷阱中断等以确保删除脚本文件名:

tmp=$(mktemp "${TMPDIR:-/tmp}/sed.script.XXXXXX")
trap "rm -f $tmp; exit 1" 0 1 2 3 13 15
sed 's/\([^ ]*\) \(.*\)/s%\1_%\2_%/' file.2 > $tmp
sed -f $tmp file.txt
rm -f $tmp
trap 0