Замените содержимое группы захвата регулярного выражения, используя sed


16

Я пытаюсь редактировать мой файл nginx.conf программно, который содержит такую ​​строку:

        access_log /var/log/nginx/access.log;

который я хочу выглядеть так:

        access_log /dev/stdout;

Я верю, что регулярное выражение ^\s*access_log([^;]*);захватит /var/log/nginx/access.logчасть в группе захвата, но я не уверен, как правильно заменить группу захвата на sed?

я пробовал

echo "        access_log /var/log/nginx/access.log;" | sed 's/^\s*access_log([^;]*);/\1\\\/dev\\\/stdout/'

но я получаю ошибку:

sed: -e expression #1, char 45: invalid reference \1 on `s' command's RHS

если я попытаюсь, sed -rто ошибки нет, но результат не соответствует ожиданиям:

 /var/log/nginx/access.log\/dev\/stdout

Я пытаюсь быть умным с группой захвата и еще много чего, а не искать напрямую "access_log /var/log/nginx/access.log;" в случае, если дистрибутив меняет расположение файла журнала по умолчанию.


1
sed '/access_log/s|/[^;]\+|/dev/stdout|'
Костас

@Costas Если бы вы ответили так, я бы вам проголосовал, так как это тоже работает!
Абе Воелкер,

Ответы:


16

Пара ошибок там.

Во-первых, поскольку sedиспользуются базовые регулярные выражения, нужно \(и \)сделать группу захвата. -rПереключатель позволяет расширенные регулярные выражения, поэтому вы не получите сообщение об ошибке. См. Почему мне нужно экранировать символы регулярного выражения в sed, чтобы интерпретировать их как символы регулярного выражения? ,

Во-вторых, вы помещаете группу захвата не в то место. Если я вас правильно понимаю, вы можете сделать это:

sed -e 's!^\(\s*access_log\)[^;]*;!\1 /dev/stdout;!' your_file

Обратите внимание на использование в !качестве разделителей регулярных выражений, чтобы избежать экранирования /dev/stdout.


Спасибо, работает чудесно! Я пока не могу пометить это как принятое, но вернусь через 9 минут.
Абе Воелкер,

1
@AbeVoelker Добро пожаловать. Я рад, что смог помочь.
Джозеф Р.

5

В своем регулярном выражении вы должны знать, что \No.это обратная ссылка на шаблон в скобках (). Так что регулярное выражение должно быть's@^(\s*access_log ).*$@\1/dev/stdout/;@'

Я могу предложить

sed '/access_log/s|/[^;]\+|/dev/stdout|'

СОВЕТ: намерены ли вы использовать /внутри патерна, вы можете изменить s///для каждого символа, который вы хотите, s###например


Спасибо, я хотел бы принять два ответа! Я больше не жалею о том, что не полностью прочитал man-страницы, прежде чем обратиться за помощью после просмотра решений.
Abe Voelker

3

Вместо того, чтобы захватить это, почему бы просто не найти это и сделать замену? То есть:

sed "/access_log/ s| /.*;| /dev/stdout;|"

Он ищет строки, которые соответствуют " access_log", а затем в любых строках, которые он заменяет, " /whatever/path/is/there;" на " /dev/stdout;"

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.