Найдите несколько шаблонов, которые включали двойные кавычки в одном файле, и прокомментируйте выше и ниже двух строк

#bash #sed #grep

Вопрос:

У меня есть очень большой файл, в котором мне нужно найти 40 шаблонов. Если шаблон совпал в файле, то нужно прокомментировать до 2 строк и после 2 строк. Шаблоны будут такими, как показано ниже:

 1.create_rev -name "2x_8_PLL"
2.create_generated_rev -name "76_L"
3.create_rev -name "PCS_T0"
4.create_generated_rev -name "x544_P"
 

Если мне нужно найти один шаблон, я могу выполнить команду gvim ниже, чтобы выполнить задачу.

 :g/create_rev -name "2x_8_PLL"/-2, 2s/^/#
 

Но шаблоны поиска больше в количестве 40 с лишним. Как искать/grep для 40 шаблонов, чтобы мой ожидаемый результат, как показано ниже:

 #pp
#oo
create_rev -name "2x_8_PLL"
#aa
#bb
hh
#ii
#jj
create_generated_rev -name "76_L"
#cc
#dd
create_rev -name "PCS_T0"
#ee
#ff
gg
 

Комментарии:

1. Вы можете использовать трубу ( | ) для разделения каждого шаблона: :g/create_rev -name "2x_8_PLL"|create_generated_rev -name "76_L"/-2, 2s/^/# . Конечно, в опубликованном примере вы также можете просто сделать :g/create/-2, 2s/^/# это, возможно, вы сможете придумать один или несколько шаблонов, которые в совокупности захватят 40, которые вы хотите (может быть, что-то вроде :g/create_.* -name ".*"/-2, 2s/^/# )

2. @mattb, Да, я могу использовать трубопровод и сделать то же самое в gvim .. но мне нужно сделать это либо в sed, либо в grep, либо в bash с помощью массива. Я не могу использовать .* создайте шаблон в моем случае.

3. awk ниже приведено то, что я бы использовал. Если вам действительно нужно sed искать sed -f script.sed input > output типовые решения. Некоторые идеи см. в руководстве sed . Удачи.

Ответ №1:

Это может сработать для вас (GNU grep и sed):

 grep -A2 -B2 -nFf targets file |sed -En 's/^([0-9] )-.*/1s@^@#@/p' |sed -f - file
 

Используйте grep для вывода строк в файле, соответствующих строкам в целевых объектах. Совпадения будут пронумерованы строками и содержать две строки до и после совпадений.

Строки, выводимые командой grep, передаются в sed и используются в качестве адресов для сценария sed, который вставляет a # в начале каждого соответствующего адреса.

Сценарий sed, созданный в результате первого вызова sed (с помощью опции -f командной строки и - с использованием stdin из канала), используется во втором вызове sed, который редактирует исходный файл.

Другое решение, использующее только sed:

 sed -E 's/.*/\#\n.*\namp;\n.*\n#bb/' targets |
sed -Ee ':a;N;s/n/amp;/4;Ta' -f - -e 'bc;:b;s/^([^#])/#1/mg;s/^#//m3;:c;P;D' file
 

Ответ №2:

Предполагая, что, когда вы говорите «шаблон», то, что вы действительно хотите,-это соответствие строк в полной строке, затем используйте любой awk в любой оболочке на каждом блоке Unix и обрабатывайте случаи перекрытия диапазонов, комментируя их как предположительно необходимые, а не дважды комментируя их, как это может произойти с другими решениями:

 $ cat tst.awk
ARGIND==1 {
    targets[$0]
    next
}
ARGIND==2 {
    if ($0 in targets) {
        for (i=FNR-2; i<=FNR 2; i  ) {
            if (i != FNR) {
                hits[i]
            }
        }
    }
    next
}
FNR in hits {
    $0 = "#" $0
}
{ print }
 
 $ awk -f tst.awk targets file file
#pp
#oo
create_rev -name "2x_8_PLL"
#aa
#bb
hh
#ii
#jj
create_generated_rev -name "76_L"
#cc
#dd
create_rev -name "PCS_T0"
#ee
#ff
gg
 
 $ cat targets
create_rev -name "2x_8_PLL"
create_generated_rev -name "76_L"
create_rev -name "PCS_T0"
create_generated_rev -name "x544_P"
 

вышесказанное использует GNU awk для ARGIND. Если у вас нет GNU awk, перейдите ARGIND==1 на FILENAME==ARGV[1] и ARGIND==2 на FILENAME==ARGV[2] .

Комментарии:

1. Повторяется ли «очень большой файл» дважды?

2. @ceving да, это повторяется дважды с помощью простого, надежного, чрезвычайно быстрого кода, использующего очень мало памяти (для всех, кроме 40 строк, все, что произойдет на первой итерации,-это поиск хэша, и то же самое для не более 160 строк на второй итерации), в отличие от повторения один раз с некоторой комбинацией более сложного, хрупкого, более медленного и более интенсивного кода с памятью.

Ответ №3:

Если ed доступно/приемлемо с некоторой помощью оболочки.

Сценарий myscript

 #!/bin/sh

targets=$1
file=$2

{
ed -s "$targets" <<'EOF'
g|.|t.
-1s|^|g/|
s|$|/-2; 1s/^\(#\)\{0,1\}\(.*\)/#\2/\|
 1s|.*|; 2; 1s/^\(#\)\{0,1\}\(.*\)/#\2/|
$a
,p
Q
.
,p
Q
EOF
} | ed -s "$file"
 

 ./myscript targets file
 
  • Удалите первый ,p , чтобы отключить вывод в stdout
  • Измените первое Q значение на w , если требуется редактирование на месте.
  • Проблемы с памятью ed могут возникать в зависимости от того, насколько она велика big file .