29

I'm trying to edit my nginx.conf file programmatically, which contains a line like this:

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

which I want to look like this:

        access_log /dev/stdout;

I believe the regex ^\s*access_log([^;]*); will capture the /var/log/nginx/access.log part in a capture group, but I'm not sure how to correctly replace the capture group with sed?

I've tried

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

but I'm getting the error:

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

if I try sed -r then there is no error, but the output is not what I expect:

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

I'm trying to be smart with the capture group and whatnot and not search directly for "access_log /var/log/nginx/access.log;" in case the distribution changes the default log file location.

0

3 Answers 3

35

A couple of mistakes there.

First, since sed uses basic regular expressions, you need \( and \) to make a capture group. The -r switch enables extended regular expressions which is why you don't get the error. See Why do I need to escape regex characters in sed to be interpreted as regex characters?.

Second, you are putting the capture group in the wrong place. If I understand you correctly, you can do this:

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

Note the use of ! as regex delimiters to avoid having to escape the forward slashes in /dev/stdout.

0
7

In your regexp you should know that \No. is the back reference to pattern within brackets (). So regexp should be 's@^(\s*access_log ).*$@\1/dev/stdout/;@'

I can offer

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

HINT: Whether you intend to use / inside the patern you are free to change s/// for every symbol you'd like s### for example

0
5

Rather than capture it, why not just find it and do a substitution? I.e.:

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

It searches for lines that match "access_log" then on any lines that do it will replace " /whatever/path/is/there;" with " /dev/stdout;"

2
  • 1
    The /access_log/ string in Jeremy's is known as an "address" for the sed command. Often, numbers (indicating line numbers) are used as addresses to sed but today I learned that regular expressions can be used as addresses too. Thanks Jeremy!
    – dgtc
    Mar 17, 2021 at 16:58
  • 1
    Thanks for the note dgtc - I learned something too! I knew that the line numbers were an "address", but it never occurred to me that a search string was also an "address" (it seems obvious now, I just hadn't made the connection...). :) Mar 17, 2021 at 19:34

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.