如何使用sed替换基于两个列表的文本文件的字符串



我有一个这样的文本文件:

test.list

##a
##b
##C
#CHROM  0_62000_1       0_62000_5       0_62070_19        0_62000

我有OLD_SM.list

0_62000_1
0_62000
0_62070_19

和NEW_SM.list

APPLE
BANANA
KIWI

我想用NEW_SM.list.替换test.list中与OLD_SM.list匹配的单词

我更喜欢sed命令,所以我尝试了这样的方法,但不起作用。

paste OLD_SM.list NEW_SM.list | while read OLD_SM NEW_SM; do sed -i "/^#CHROM/s/[[:space:]]${OLD_SM}$/t${NEW_SM}/g" test.list; done

结果我想要

##a
##b
##C
#CHROM  APPLE       0_62000_5       KIWI        BANANA

使用GNU sed,您可以将单词的开头和结尾与<>相匹配。您可以首先根据输入生成一个sed脚本,然后将其传递给sed。输入中必须没有特殊字符。

script=$(
paste OLD_SM.list NEW_SM.list |
sed 's/(.*)t(.*)/s~\<1\>~2~g/'
)
sed -i "/^#CHROM/{ $script }" file.

s/[[:space:]]${OLD_SM}$-$匹配行的末尾,所以它永远不会工作。您可以执行s/(^|[[:space:]])$OLD_SM([[:space:]]|$)/1$NEW_SM2/-匹配行或空格的开头,然后匹配单词,然后匹配空格或行的结尾,然后替换backreference。研究主题:正则表达式和sed中的backreferences。

您可以使用以下paste + awk解决方案:

awk -v OFS='t' 'NR == FNR { map[$1]=$2; next} $1 == "#CHROM" {for (i=2; i<=NF; ++i) $i in map && $i=map[$i]} 1' <(paste OLD_SM.list NEW_SM.list) test.list
##a
##b
##C
#CHROM  APPLE   0_62000_5   KIWI    BANANA

扩展形式:

awk -v OFS='t' '
NR == FNR {
map[$1] = $2
next
}
$1 == "#CHROM" {
for (i=2; i<=NF; ++i)
$i in map && $i = map[$i]
}
1' <(paste OLD_SM.list NEW_SM.list) test.list

略有不同:将sed程序构建为bash数组:

sed_opts=()
while read -r old <&3; read -r new <&4; do
sed_opts+=( -e "s/\<$old\>/$new/g" )
done 3< OLD_SM.list 4< NEW_SM.list
sed "${sed_opts[@]}" test.list

相关内容

  • 没有找到相关文章

最新更新