sed:仅使用变量列表替换模式一次

sed:仅使用变量列表替换模式一次

我是 sed 新手,想知道如何每次用不同的变量替换模式

我有一个 txt 文件,如下所示:

@K3KFV:1:1109:11598:25872
@K3KFV:1:2101:22577:15247
@K3KFV:1:1110:13477:13178
@K3KFV:1:2113:23585:6859... (etc)

总共有 200 条不同的线路。另外我还有另一个文件:

ASF356_KB822565.1:1065516-1065795
TAGGTCAAGCCCTCGGTCTATTAGTATTGGTCAGCTTAATACATTGCTGCACTTACACCT
CCAACCTATCTACCTTGTTGTCTTCAAGGGACCTTACTCACTTGCGTTTTGGGATATCTT
 
ASF356_KB822565.1:1065796-1066075
CGGATAGGGACCGAACTGTCTCACGACGTTCTGAACCCAGCTCGCGTACCGCTTTAATGG
GCGAACAGCCCAACCCTTGGGACCTACTTCAGCCCCAGGATGCGATGAGCCGACATCGAG
 
ASF356_KB822565.1:1066076-1066355
CCTTTTGCCTTTACACTCTTTGAATGGTTTCCAATCATTCTGAGGTGACCTTCGAGCGCC
TCCGTTACTCTTTTGGAGGCGACCGCCCCAGTCAAACTGCCCGCCTGACATTGTCCTTCA

其中还包含 200 个“ASF.....”实例

我想要的是将包含“ASF...”的行替换为“@K3KFV:.....”中的行,所以最后它看起来像:

@K3KFV:1:1109:11598:25872
TAGGTCAAGCCCTCGGTCTATTAGTATTGGTCAGCTTAATACATTGCTGCACTTACACCT
CCAACCTATCTACCTTGTTGTCTTCAAGGGACCTTACTCACTTGCGTTTTGGGATATCTT

@K3KFV:1:2101:22577:15247
CGGATAGGGACCGAACTGTCTCACGACGTTCTGAACCCAGCTCGCGTACCGCTTTAATGG
GCGAACAGCCCAACCCTTGGGACCTACTTCAGCCCCAGGATGCGATGAGCCGACATCGAG

@K3KFV:1:1110:13477:13178
CCTTTTGCCTTTACACTCTTTGAATGGTTTCCAATCATTCTGAGGTGACCTTCGAGCGCC
TCCGTTACTCTTTTGGAGGCGACCGCCCCAGTCAAACTGCCCGCCTGACATTGTCCTTCA

这是我到目前为止的 shell 脚本:

input="K3KFVfile.txt"

while IFS= read -r title
do
        sed '/ASF/c'$title'' ASF_file
done < "$input"

但我没有给我 200 行 @K3KFV...而是得到了 40000 行,因为每条 ASF 行都被每一条 @K3KFV 行替换。

有没有办法在继续之前使用 sed 仅使用变量替换一次模式?在这种情况下 sed 是正确的命令吗?

答案1

如果您有 sed 的 GNU 实现,您可以使用(大写)命令R- 它的其中之一GNU sed 特有的命令ASF- 每次与第二个文件中以开头的行匹配时,读取并插入第一个文件的一行。然后删除匹配的行:

$ sed '/^ASF/{
R K3KFVfile.txt
d
}' ASF_file
@K3KFV:1:1109:11598:25872
TAGGTCAAGCCCTCGGTCTATTAGTATTGGTCAGCTTAATACATTGCTGCACTTACACCT
CCAACCTATCTACCTTGTTGTCTTCAAGGGACCTTACTCACTTGCGTTTTGGGATATCTT

@K3KFV:1:2101:22577:15247
CGGATAGGGACCGAACTGTCTCACGACGTTCTGAACCCAGCTCGCGTACCGCTTTAATGG
GCGAACAGCCCAACCCTTGGGACCTACTTCAGCCCCAGGATGCGATGAGCCGACATCGAG

@K3KFV:1:1110:13477:13178
CCTTTTGCCTTTACACTCTTTGAATGGTTTCCAATCATTCTGAGGTGACCTTCGAGCGCC
TCCGTTACTCTTTTGGAGGCGACCGCCCCAGTCAAACTGCCCGCCTGACATTGTCCTTCA

如果您愿意,可以将其写为一行:

sed -e '/^ASF/{R K3KFVfile.txt' -e 'd}' ASF_file

或者你可以考虑使用 awk:

awk 'NR==FNR{K[FNR] = $0; next} /^ASF/{$0 = K[++n]} 1' K3KFVfile.txt ASF_file

答案2

这个答案有点即兴发挥@steeldriver的

如果 ASF_file 中的空白行确实是空的(没有空格),那么这个 awk 就可以工作

awk '
    NR == FNR {x[FNR] = $0; next}
    {$1 = x[FNR]; print}
' K3KFVfile.txt RS='' ORS='\n\n' FS='\n' OFS='\n' ASF_file

在开始读取第二个文件之前,我更改了一些 awk 变量来控制如何确定记录和字段。我通常不喜欢这种风格,但它在这里效果很好。这个 GNU awk 版本更整洁一些

gawk '
    NR == FNR {x[FNR] = $0; next}
    ENDFILE {RS = ""; ORS = "\n\n"; FS = OFS = "\n"}
    {$1 = x[FNR]; print}
' K3KFVfile.txt ASF_file

答案3

使用awk

awk '/^ASF/ {getline < "@K3FVfile.txt"};1' ASF_file

同样的事情在Perl

perl -pe 's/^ASF.*/<STDIN>/se' ASF_file < @K3FVfile.txt

使用 POSIXly sed:

sed -n '/\n/bh
  1{
    :k3
      H;1h;n
    /^@K3KFV/bk3
  }
  /^ASF/g
  P;/\n.*\n/D
  s/.*\n//;th
  d;:h
  h
' @K3FVfile.txt ASF_file

在 Python 中使用列表理解:

python3 -c 'import sys;a,b = sys.argv[1:]
with open(a) as f, open (b) as g:
  print(*[next(f) if l.startswith("ASF") else l for l in g],sep="",end="")
' @K3FVfile.txt ASF_file

输出 :

@K3KFV:1:1109:11598:25872
TAGGTCAAGCCCTCGGTCTATTAGTATTGGTCAGCTTAATACATTGCTGCACTTACACCT
CCAACCTATCTACCTTGTTGTCTTCAAGGGACCTTACTCACTTGCGTTTTGGGATATCTT
 
@K3KFV:1:2101:22577:15247
CGGATAGGGACCGAACTGTCTCACGACGTTCTGAACCCAGCTCGCGTACCGCTTTAATGG
GCGAACAGCCCAACCCTTGGGACCTACTTCAGCCCCAGGATGCGATGAGCCGACATCGAG
 
@K3KFV:1:1110:13477:13178/
CCTTTTGCCTTTACACTCTTTGAATGGTTTCCAATCATTCTGAGGTGACCTTCGAGCGCC
TCCGTTACTCTTTTGGAGGCGACCGCCCCAGTCAAACTGCCCGCCTGACATTGTCCTTC

相关内容