下面是一个玩具文本文件,其中包含样本和特征信息以及测量值。
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循环做的事情吗?我可以循环遍历单个列(逐行),但我不知道如何处理匹配的列。
非常感谢任何帮助。
答案 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代码中没有循环。注意模式中的_
;这对于阻止Sample3
将Sample300
映射到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