Вопрос или проблема
Я пытаюсь раскомментировать конкретные строки из файла с шаблонами в Oracle Linux 8.6, используя Bash. В некоторых строках есть ведущие пробелы, где комментарии не удаляются. Я пытался раскомментировать закомментированные строки с помощью sed и grep для совпадения с шаблонами.
sed -n '/\<19\>/,+1p' cmfile|grep '38'|sed -i '/38/s/^#//g' cmfile
Содержимое файла:
#pd19_ORA svg38
#pd19_ORA sil38
#pd29_ORA sil37
Первая строка все еще закомментирована после использования sed с inplace, но комментарий второй строки удален.
Вывод:
#pd19_ORA svg38
pd19_ORA sil38
#pd29_ORA sil37
Как удалить комментарий у первой строки, которая имеет ведущие пробелы, не удаляя ведущий пробел?
Ожидаемый вывод:
pd19_ORA svg38
pd19_ORA sil38
#pd29_ORA sil37
Вы можете попробовать awk
, и следующая команда может сделать это. Если вам нужно, чтобы конкретные строки 19
и 38
находились на определенных местах, вы должны указать это в вопросе:
awk '/19/ && /38/ {sub(/#/,"")}1'
Эта команда ищет строку с 19
и 38
и удаляет символ #
. Затем выводит строку (независимо от того, совпадает она и редактирована или нет)
awk '/19/ && /38/ {sub(/#/,"")}1' input_file
pd19_ORA svg38
pd19_ORA sil38
#pd29_ORA sil37
Если вы хотите убедиться, что #
является первым символом, который не является пробелом в строке, вы можете модифицировать скрипт следующим образом:
awk '/19/ && /38/ && $1 ~ "^#" {sub(/#/,"")}1' input_file
Предположим, вы хотите раскомментировать строки, которые содержат 38, и которые следуют за строкой, содержащей словоограниченное¹ 19
, как предполагает ваша попытка:
perl -pi -e 's/^\s*\K#// if $flag && /38/; $flag = /\b19\b/' your-file
В вашем:
sed -n '/\<19\>/,+1p' cmfile|grep '38'|sed -i '/38/s/^#//g' cmfile
Команда sed -i '/38/s/^#//g' cmfile
не читает свой ввод, она только редактирует cmfile
на месте, удаляя ведущий #
на любой строке, содержащей 38
(кстати, g
избыточно, так как может быть только одна подстановка).
Таким образом, sed -n '/\<19\>/,+1p' cmfile|grep '38'
бессмысленен, так как ничего не читает его вывод.
Также обратите внимание, что все -i
, +1
, \<\>
являются нестандартными расширениями GNU², в то время как команда perl
будет работать на любой системе³.
¹ В любом случае, 19
в pd19_ORA
не является словоограниченным, так как и d
, и _
являются словесными символами; если вы хотите сопоставить 19
, который не является ни предшествующим, ни следующим десятичным числом, используйте (?<!\d)19(?!\d)
вместо \b19\b
(эквивалент perl для ex
‘ \<19\>
).
² Строго говоря, \<\>
возникло в ex
/vi
, а не GNU sed
, и -i
было скопировано GNU sed
из perl
, а ,+1
из ed
.
³ Хотя вам потребуется perl версии 5.10.0 (с 2007 года) или новее для \K
(чтобы K
eep сохранить то, что слева от него). На системах с более старой версией perl
вы можете заменить s/^\s*\K#//
на s/^(\s*)#/$1/
.
^#
соответствует только #
в начале строки. Одной из альтернатив для разрешения пробелов перед комментарием является ^[ \t]*#
Итак, эта строка должна работать:
sed -n '/\<19\>/,+1p' cmfile|grep '38'|sed -i '/38/s/^[ \t]*#//g' cmfile
Я думаю, вы хотите удалить лидирующий символ #
из всех строк, содержащих число 19
, сохраняя любые ведущие пробелы
sed -E '/[^0-9]19([^0-9]|$)/s/^([[:space:]]*)#/\1/' cmfile
Это ищет строки, содержащие 19
(но без цифр по обе стороны, таких как 019
или 193
), так как я не мог заставить \<19\>
соответствовать любой из ваших строк здесь.
В случае, если вы хотите, чтобы строки содержали 19
и 38
, вам просто нужно расширить исходное соответствие строки:
sed -E '/[^0-9]19([^0-9]|$)(.*[^0-9]|)38([^0-9]|$)/s/^([[:space:]]*)#/\1/' cmfile
В обоих случаях для всех таких совпадающих строк мы захватываем любые ведущие пробелы, предшествующие символу #
, чтобы мы могли добавить их обратно в вывод
Ответ или решение
Для решения проблемы удаления символа #
из строк, содержащих определенные шаблоны, на Oracle Linux 8.6 с использованием Bash, нужно учесть наличие ведущих пробелов в строках. Ваш текущий подход с использованием sed
имеет некоторые ограничения, поскольку он не обрабатывает ведущие пробелы правильно из-за специфики поиска по началу строки. Рассмотрим несколько альтернативных методов решения этой задачи.
Решение с использованием awk
awk
является мощным инструментом для обработки текстовых данных в Unix-подобных системах. Пользуйтесь awk
, чтобы упростить задачу по удалению #
в нужных строках, сохранив при этом ведущие пробелы:
awk '/19/ && /38/ {sub(/^[ \t]*#/, "")}1' cmfile
Объяснение
- Поиск строк: Команда ищет строки, которые содержат как
19
, так и38
. - Удаление комментария: Функция
sub
заменяет комментарий#
в начале строки, сохраняя при этом любые ведущие пробелы. - Вывод результата:
1
в конце команды указывает на то, что каждая строка, независимо от того, была ли она изменена, должна быть выведена.
Решение с использованием perl
perl
также широко используется для сложных текстовых трансформаций и поддерживает регексы, которые могут быть недостаточно мощными в sed
:
perl -pi -e 's/^\s*#// if /19/ && /38/' cmfile
Объяснение
- Условие поиска: Команда ищет совпадение строк, содержающих
19
и38
. - Удаление комментария: Используется конструкция
s/^\s*#//
, которая удаляет символ#
при его нахождении в начале строки, игнорируя ведущие пробелы.
Решение с использованием расширенного sed
Если вы все-таки предпочитаете sed
, нужно адаптировать команду, чтобы она учитывала ведущие пробелы:
sed -i -E '/19/ && /38/ s/^[ \t]*#//' cmfile
Объяснение
- Поиск строк: Используется расширенный формат регулярных выражений от
sed
с опцией-E
. - Удаление комментария: Шаблон
^[ \t]*#
позволяет корректно обрабатывать строки с лидирующими пробелами перед#
.
Заключение
Каждый из этих методов имеет свои преимущества. Выберите подходящий, исходя из ваших предпочтений и установленных инструментов. Эти команды исправят текущие проблемы в вашем скрипте и позволят легко удалять символы комментария из строк с нужным шаблоном, сохраняя их форматирование. Убедитесь, что вы используете инструменты, которые соответствуют совместимости вашей системы, чтобы избежать нежелательных результатов или ошибок.