Unix 替换文本文件中不以特定字符开头的行上的特定列

Unix 替换文本文件中不以特定字符开头的行上的特定列,unix,awk,sed,Unix,Awk,Sed,我有一个如下所示的文本文件: >long_name AAC-TGA >long_name2 CCTGGAA 以及列编号列表:2、4、7。当然,我可以将其作为变量,如: cols="2 4 7" 我需要用单个字符(例如N)替换不以开头的每一列行,以产生以下结果: >long_name ANCNTGN >long_name2 CNTNGAN 其他详细信息-该文件有约200K行。所有不以>开头的行的长度都相同。行索引永远不会超过非行的长度 在我看来,sed和awk的某种组

我有一个如下所示的文本文件:

>long_name
AAC-TGA
>long_name2
CCTGGAA
以及列编号列表:
2、4、7
。当然,我可以将其作为变量,如:

cols="2 4 7"
我需要用单个字符(例如
N
)替换不以
开头的每一列行,以产生以下结果:

>long_name
ANCNTGN
>long_name2
CNTNGAN
其他详细信息-该文件有约200K行。所有不以
>
开头的行的长度都相同。行索引永远不会超过非
行的长度

在我看来,sed和awk的某种组合必须能够快速做到这一点,但我一辈子都不知道如何将它们联系在一起

例如,我可以使用sed处理不是以
开头的所有行,如下所示(在这种情况下,将所有空格替换为
N
):

我可以使用AWK替换特定的行列,因为我想这样做(我想…):


但我正在努力用GNU awk将其缝合起来,将I/o字段分隔符设置为空字符串,以便每个字符都成为一个字段,并且您可以轻松地更新它们

awk -v cols='2 4 7' '
BEGIN {
  split(cols,f)
  FS=OFS=""
}
!/^>/ {
  for (i in f)
    $(f[i])="N"
}
1' file

另请参见。

您可以先生成替换命令列表,然后将其传递给
sed

$ printf '2 4 7' | sed -E 's|[0-9]+|/^>/! s/./N/&\n|g'
/^>/! s/./N/2
 /^>/! s/./N/4
 /^>/! s/./N/7
$ printf '2, 4, 7' | sed -E 's|[^0-9]*([0-9]+)[^0-9]*|/^>/! s/./N/\1\n|g'
/^>/! s/./N/2
/^>/! s/./N/4
/^>/! s/./N/7

$ sed -f <(printf '2 4 7' | sed -E 's|[0-9]+|/^>/! s/./N/&\n|g') ip.txt
>long_name
ANCNTGN
>long_name2
CNTNGAN

在每个UNIX设备上的任何shell中使用任何awk:

$ awk -v cols='2 4 7' '
    BEGIN { split(cols,c) }
    !/^>/ { for (i in c) $0=substr($0,1,c[i]-1) "N" substr($0,c[i]+1) }
1' file
>long_name
ANCNTGN
>long_name2
CNTNGAN

您可以将sed
-e
-f
混合一次或多次,并且
-f
接受
-
作为标准输入,因此
在使用awk时不需要sed。
$ printf '2 4 7' | sed -E 's|[0-9]+|/^>/! s/./N/&\n|g'
/^>/! s/./N/2
 /^>/! s/./N/4
 /^>/! s/./N/7
$ printf '2, 4, 7' | sed -E 's|[^0-9]*([0-9]+)[^0-9]*|/^>/! s/./N/\1\n|g'
/^>/! s/./N/2
/^>/! s/./N/4
/^>/! s/./N/7

$ sed -f <(printf '2 4 7' | sed -E 's|[0-9]+|/^>/! s/./N/&\n|g') ip.txt
>long_name
ANCNTGN
>long_name2
CNTNGAN
$ printf '2 4 7' | sed -E 's|^|/^>/!{|; s|[0-9]+|s/./N/&; |g; s|$|}|'
/^>/!{s/./N/2;  s/./N/4;  s/./N/7; } 
$ awk -v cols='2 4 7' '
    BEGIN { split(cols,c) }
    !/^>/ { for (i in c) $0=substr($0,1,c[i]-1) "N" substr($0,c[i]+1) }
1' file
>long_name
ANCNTGN
>long_name2
CNTNGAN