Замініть вміст групи захоплення регулярних виразів за допомогою 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 Якщо ви зробите цю відповідь, я б підтримав вас, оскільки це також працює!
Abe Voelker

Відповіді:


16

Пару помилок там.

По- перше, так як sedвикористань основні регулярні вирази, вам потрібно \(і \)зробити захоплення групи. -rПеремикач дозволяє розширені регулярні вираження, тому ви не отримаєте повідомлення про помилку. Див. Чому мені потрібно уникати символів регулярних виразів у sed, щоб їх інтерпретувати як символи регулярних виразів? .

По-друге, ви ставите групу захоплення в неправильне місце. Якщо я вас правильно зрозумів, ви можете це зробити:

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

Зверніть увагу на використання !розмежувачів, які регулярно виражають, щоб уникнути необхідності уникнути нахилу вперед /dev/stdout.


Дякую, чудово працює! Я не в змозі відзначити це як прийняте, але повернусь через 9 хвилин.
Abe Voelker

1
@AbeVoelker Ви дуже раді. Я радий, що можу допомогти.
Джозеф Р.

5

У вашому regexp слід знати, що \No.це зворотне посилання на візерунок у дужках (). Значить, регулярне вираження повинно бути's@^(\s*access_log ).*$@\1/dev/stdout/;@'

Я можу запропонувати

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

Підказка: Незалежно від того, чи плануєте ви використовувати /всередині патерни, ви можете змінювати s///кожен символ, який ви хочете, s###наприклад


Дякую, я хотів би прийняти дві відповіді! Я більше не шкодую, що не прочитав повністю чоловічих сторінок, перш ніж попросити допомоги, побачивши рішення.
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.