我是 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