Как заменить содержимое между 2 тегами на SED (bash)?

#awk #sed

Вопрос:

Я хочу на месте отредактировать файл с sed помощью (Oracle-Linux/Bash).

Содержимое между 2 поисковыми тегами (в форме «#»-комментариев) должно быть закомментировано.

Пример:

 Some_Values
#NORMAL_LISTENER_START
LISTENER =
  (DESCRIPTION =
    (ADDRESS = (PROTOCOL = IPC)
         (KEY      = LISTENER)
    )
  )
)
#NORMAL_LISTENER_END
Other_Values
 

Должно привести к:

 Some_Values    
#NORMAL_LISTENER_START
# LISTENER =
#   (DESCRIPTION =
#     (ADDRESS = (PROTOCOL = IPC)
#          (KEY      = LISTENER)
#     )
#   )
# )
#NORMAL_LISTENER_END
Other_Values
 

Следующая команда уже достигает этого, но она также помещает комментарий пробел перед тегами поиска:

 sed -i "/#NORMAL_LISTENER_START/,/#NORMAL_LISTENER_END/ s/^/# /" ${my_file}
 

Теперь мое исследование подсказало мне исключить такие теги поиска, как:

 sed -i '/#NORMAL_LISTENER_START/,/#NORMAL_LISTENER_END/{//!p;} s/^/# /' ${my_file}
 

Но это не сработает — в результате появится следующее сообщение:

sed: -выражение e #1, символ 56: дополнительные символы после команды

Мне нужно, чтобы эти поисковые теги были такими, какие они есть, потому что они мне потом снова понадобятся.

Ответ №1:

Если ed доступно/приемлемо.

 printf '%sn' 'g/#NORMAL_LISTENER_START/ 1;/#NORMAL_LISTENER_END/-1s/^/#/' ,p Q | ed -s file.txt
 
  • Измените Q значение на w , если вы удовлетворены выводом, и произойдет редактирование на месте.
  • Удалите ,p , если вы не хотите видеть результат.

Ответ №2:

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

 sed '/#NORMAL_LISTENER_START/,/#NORMAL_LISTENER_END/{//!s/^/# /}' file
 

Используйте диапазон, разделенный двумя регулярными выражениями, и вставляйте # перед строками между регулярными выражениями, но не включая регулярные выражения.

Альтернатива:

 sed '/#NORMAL_LISTENER_START/,/#NORMAL_LISTENER_END/{s/^[^#]/# amp;/}' file
 

Или, если вы предпочитаете:

 sed '/#NORMAL_LISTENER_START/{:a;n;/#NORMAL_LISTENER_END/!s/^/# /;ta}' file
 

Ответ №3:

Только с показанными вами образцами, пожалуйста, попробуйте выполнить следующий awk код. Простое объяснение было бы следующим: найдите конкретную строку и установите/снимите значения vars в соответствии с этим, а затем распечатайте обновленные(добавленные # в строках) строки в соответствии с этим, прекратите обновление строк, как только мы найдем строку, из которой нам не нужно обновлять строки.

 awk ' /Other_Values/{found=""} found{$0=$0!~/^#/?"#"$0:$0} /Some_Values/{found=1} 1' Input_file
 

Выше будет выведен вывод на терминале, как только вы будете довольны результатами, вы можете запустить следующий код, чтобы сохранить его в Input_file.

 awk ' /Other_Values/{found=""} found{$0=$0!~/^#/?"#"$0:$0} /Some_Values/{found=1} 1' Input_file > temp amp;amp; mv temp Input_file
 

Пояснение: Добавление подробного объяснения вышеизложенного.

 awk '                                    ##Starting awk program from here.
/Other_Values/{ found=""             }   ##If line contains Other_Values then nullify found here.  
found        {  $0=$0!~/^#/?"#"$0:$0 }   ##If found is SET then check if line already has # then leave it as it is OR add # in starting to it.
/Some_Values/{ found=1               }   ##If line contains Some_Values then set found here.
1                                        ##Printing current line here.
' Input_file                             ##Mentioning Input_file name here.
 

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

1. Все работает нормально — это немного некрасиво с созданием временного файла. Есть ли способ сделать это без этого?

2. @Dannxy, конечно, в GNU Awk 4.1.0 (выпущен в 2013 году) и более поздних версиях есть возможность редактирования на месте, затем попробуйте выполнить следующее: gawk -i inplace ' /Other_Values/{found=""} found{$0=$0!~/^#/?"#"$0:$0} /Some_Values/{found=1} 1' Input_file

3. @Dannxy, теперь я также добавил подробное объяснение в свое решение.

4. Похоже, нам придется использовать GNU Awk 4.0.2 — поэтому я должен придерживаться временного файла. Но все в порядке, ты спасла мне день. Спасибо! Приветствую!