16

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.

  • 1
    sed '/access_log/s|/[^;]\+|/dev/stdout|' – Costas Nov 2 '14 at 20:50
  • @Costas If you would make that an answer I'd upvote you as that also works! – Abe Voelker Nov 2 '14 at 20:51
15

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.

  • Thanks, works wonderfully! I'm not able to mark this as accepted yet, but will be back in 9 minutes to do so. – Abe Voelker Nov 2 '14 at 20:50
  • 1
    @AbeVoelker You're very welcome. I'm glad I could help. – Joseph R. Nov 2 '14 at 20:51
5

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

  • Thanks, I wish I could accept two answers! I no longer regret not fully reading man pages before asking for help after seeing the solutions. – Abe Voelker Nov 2 '14 at 21:05
3

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;"

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.