Заменить несколько строк в текстовом файле фиксированным шаблоном

$ echo 'F o u r  s c o r e  a n d' | \
txr -t '(mapcar* (opip (split-str @1 "  ")
                       (mapcar (op regsub #/ / ""))
                       (cat-str @1 " "))
                 (get-lines))'
Four score and


$ txr -e '(awk (:begin (set fs "  "))
               ((mf (regsub #/ / ""))))'  # mf: modify fields
F o u r  s c o r e  a n d
Four score and


$ awk -F'  ' '{for(i=1;i<=NF;i++)gsub(/ /,"",$i);print}'
F o u r  s c o r e  a n d
Four score and
2
08.05.2017, 02:49
4 ответа

Поскольку замена является статической, а операция замены нескольких строк настолько проста в sed, можно создать один большой sed скрипт для выполнения этой работы.

Предположим, что у вас есть номера строк в отдельном файле, linenos.txt, по одному номеру строки в строке, тогда мы можем создать сценарий (GNU) sed через

$ 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 справляется с этим с точки зрения производительности.

1
27.01.2020, 21:51

В качестве расширения ответа @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

(последние два эквивалентны)

3
27.01.2020, 21:51

И 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 печатает все строки после возможного преобразования, выполненного предыдущим кодом.)

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

Сначала мы заполним пространство хранения желаемым шаблоном XXXXXXXXX, а затем вызовем его только для нужных номеров строк, перейдя к метке :p, которая извлечет пространство хранения, которое затем будет неявно перенесено в стандартный вывод. Несоответствующие -строки удаляются (, измените dна b, если вы хотите их сохранить ).

2
27.01.2020, 21:51

Теги

Похожие вопросы