用固定模式替换文本文件中的多行

用固定模式替换文本文件中的多行

好吧,正在寻找一种快速的方法来做到这一点。我有一个文本数据文件中需要更改的行号列表。该行上的 16 位模式可以是任何内容,但我需要将其更改为XXXXXXXXXXXXXXXX仅根据行号进行读取。我再次有一长串我知道需要更改的行号。需要更改的线条没有明显的模式。 (我没有写数据模式,但我知道需要更改哪些行才能读取所有 X。)我阅读了这里的很多答案,但没有一个真正解决这个问题。

如果这还不清楚,我会用另一种方式来表达......

将文件中的第 26115、32198、37256、40001、40023 行更改为读取XXXXXXXXXXXXXXX.在 190 万行文件中,我有超过 100,000 行需要更改。

答案1

作为@Gilles答案的扩展,因为你说你有文件中需要更改的行号(我假设已排序并调用linums

awk '
  BEGIN { getline NEXT < "linums" }
  NR == NEXT { $0 = "XXXXXXXXXXXXXXX"; getline NEXT < "linums" }
  1
'

这可以很好地扩展以更改数千行,而无需手动键入这数千行号。

或者,通过稍加修改,您可以获取要更改的行号或文件stdin。我会为此制作一个脚本(我称之为redact.awk

#!/usr/bin/awk -f
BEGIN {
    LINUMS = ARGV[1]
    ARGV[1] = ARGV[2]
    --ARGC
    getline NEXT < LINUMS
}
NR == NEXT {
    $0 = "XXXXXXXXXXXXXXX"
    getline NEXT < LINUMS
}
1

然后您可以使用以下任何一个:

$ ./redact.awk linums file-to-be-changed
$ ./redact.awk - file-to-be-changed
$ ./redact.awk linums -
$ ./redact.awk linums

(后两者是等价的)

答案2

sed 或 awk 都可以很好地完成此任务。

sed '
    26115 s/.*/XXXXXXXXXXXXXXX/
    32198 s/.*/XXXXXXXXXXXXXXX/
    37256 s/.*/XXXXXXXXXXXXXXX/
    40001 s/.*/XXXXXXXXXXXXXXX/
    40023 s/.*/XXXXXXXXXXXXXXX/
'
awk '
  NR==26115 || NR==32198 || NR==37256 || NR==40001 || NR==40023 {$0 = "XXXXXXXXXXXXXXX"}
  1
'

1(在前面的代码执行可能的转换之后,单独的打印所有行。)

答案3

sed -e '1{x;s/^/XXXXXXXXXXXXXXX/;x;}
   26115bp
   32198bp
   37256bp
   40001bp
   40023bp
   d
   :p
   g
' data_file

我们首先用所需的模式填充保留空间XXXXXXXXX ,然后通过跳转到标签 :p 来仅调用所需的行号,该标签将检索保留空间,然后将其隐式转移到标准输出。不匹配的行将被删除(如果要保留它们,请将 更改d为)。b

答案4

由于替换是静态的,并且替换多行的操作在 中非常简单sed,因此可以创建一个sed大脚本来完成这项工作。

假设您将行号放在一个单独的文件中,linenos.txt每行一个行号,那么我们可以sed通过以下方式生成(GNU)脚本:

$ awk '{ printf("%dc XXXXXXXXXXXXXXX\n", $0) }' linenos.txt >script.sed

或者

$ awk '{ print $0, "c XXXXXXXXXXXXXXX" }' linenos.txt >script.sed

然后,将其应用到文件中:

$ sed -f script.sed file >file.new

注意:我从未运行过非常大的sed脚本,所以我不知道 GNU 如何在sed性能方面处理它。

相关内容