Unix & Linux Stack Exchange is a question and answer site for users of Linux, FreeBSD and other Un*x-like operating systems. It's 100% free, no registration required.

Sign up
Here's how it works:
  1. Anybody can ask a question
  2. Anybody can answer
  3. The best answers are voted up and rise to the top

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.

share|improve this question
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
up vote 4 down vote accepted

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.

share|improve this answer
    
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
    
@AbeVoelker You're very welcome. I'm glad I could help. – Joseph R. Nov 2 '14 at 20:51

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

share|improve this answer
    
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

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

share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

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