Take the 2-minute tour ×
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.

I have a file "test" like this:

RewiteEngine On
RewriteCond   %{REMOTE_ADDR}   !^192\.168\.1\.7$  [NC]
RewriteCond   %{REMOTE_ADDR}   !^192\.168\.1\.8$  [NC]
RewriteCond   %{REMOTE_ADDR}   !^192\.168\.1\.9$  [NC]
RewriteCond   %{REMOTE_ADDR}   ^192\.168\.1\.5$  [NC]
</Directory>

I want to replace \.1\.7,\.1\.8 and \.1\.9 by \.1\.10 so it will be:

RewiteEngine On
RewriteCond   %{REMOTE_ADDR}   !^192\.168\.1\.10$  [NC]
RewriteCond   %{REMOTE_ADDR}   ^192\.168\.1\.5$  [NC]
</Directory>

it might be replacement of m "IPS" by n "IPS", How can I reach this?

share|improve this question

4 Answers 4

up vote 4 down vote accepted

A perl solution:

$ perl -ple 's/\\\.1\\\.(7|8|9)/\\.1\\.10/' file | uniq
RewiteEngine On
RewriteCond   %{REMOTE_ADDR}   !^192\.168\.1\.10$  [NC]
RewriteCond   %{REMOTE_ADDR}   ^192\.168\.1\.5$  [NC]
</Directory>

If you want edit inplace, you can try:

perl -i.bak -nle 'next if $count and /!\^/;s/\\\.1\\\.(7|8|9)/\\.1\\.10/ and $count++ if /!\^/;print' file
share|improve this answer
    
Thanks, but are there other ways without using perl –  Networker Aug 4 at 14:00
    
@Networker All perl is doing here is regex substitution. You can use sed in the same way if you don't like perl (and if you don't, shame on you!) –  Joseph R. Aug 4 at 14:12
    
@JosephR., I like perl (I like all scripting language indeed) but I want to benefit from Gnouc in more than one way. –  Networker Aug 4 at 17:06
1  
A more readable (for certain definitions of "readable") version of the regex could be: s/\Q\.1\.\E\K(7|8|9)/10/ –  Joseph R. Aug 4 at 19:35
1  
@JosephR.: Nice one! Forgot about \Q, \E –  cuonglm Aug 4 at 19:41

I have managed to do this by deleting all the lines and reinserting them, but I want an optimal solution (because here is deleting the whole line then adding a new whole line) and I want to add white spaces to the added lines:

delete:

sed -i '/!^.*$/d' test2

insert back:

 sed -i '/RewiteEngine On/aRewriteCond   %{REMOTE_ADDR}   !^192\.168\.1\.10$  [NC]' test2

the output is:

  RewiteEngine On
RewriteCond   %{REMOTE_ADDR}   !^192.168.1.10$  [NC] # need whites spaces at the begining
  RewriteCond   %{REMOTE_ADDR}   ^192\.168\.1\.5$  [NC]
share|improve this answer
sed '/!/d;/\(\^[^5]*\)./{h;s//!\110/p;g;}' <<\DATA
RewiteEngine On
RewriteCond   %{REMOTE_ADDR}   !^192\.168\.1\.7$  [NC]
RewriteCond   %{REMOTE_ADDR}   !^192\.168\.1\.8$  [NC]
RewriteCond   %{REMOTE_ADDR}   !^192\.168\.1\.9$  [NC]
RewriteCond   %{REMOTE_ADDR}   ^192\.168\.1\.5$  [NC]
</Directory>
DATA

OUTPUT

RewiteEngine On
RewriteCond   %{REMOTE_ADDR}   !^192\.168\.1\.10$  [NC]
RewriteCond   %{REMOTE_ADDR}   ^192\.168\.1\.5$  [NC]
</Directory>

So this relies on the s/ubsti/tution/ matching the last address - which it will do. When an /address/ is empty like s// or // the previous address is implied. It deletes all of /!/ lines containing a bang, then it addresses on a line with a ^ and puts that into hold-space. Then it edits it, prints it, and overwrites it again with its original value still in hold space.

But if the match address could match the hold line and the edited lines, then you could just keep editing them. Maybe like this:

sed '/!/d;/\(\^[^$]*\.\)[0-9]*/{h;s//!\110/p;s//\111/p;s//\112/p;g;}' <<\DATA
RewiteEngine On
RewriteCond   %{REMOTE_ADDR}   !^192\.168\.1\.7$  [NC]
RewriteCond   %{REMOTE_ADDR}   !^192\.168\.1\.8$  [NC]
RewriteCond   %{REMOTE_ADDR}   !^192\.168\.1\.9$  [NC]
RewriteCond   %{REMOTE_ADDR}   ^192\.168\.1\.5$  [NC]
</Directory>
DATA

OUTPUT

RewiteEngine On
RewriteCond   %{REMOTE_ADDR}   !^192\.168\.1\.10$  [NC]
RewriteCond   %{REMOTE_ADDR}   !^192\.168\.1\.11$  [NC]
RewriteCond   %{REMOTE_ADDR}   !^192\.168\.1\.12$  [NC]
RewriteCond   %{REMOTE_ADDR}   ^192\.168\.1\.5$  [NC]
</Directory>

Honestly, though, anymore than that and you'd probably want to approach it a little differently. Maybe with printf?

ips() { printf 's//\\1%d/p;' $(seq "$@") ; echo 'g;}' ; }

sed '/!/d;/\(\^[^$]*\.\)[0-9]*/{h;s//!\110/p;'"$(ips 11 30)" <<\DATA
RewiteEngine On
RewriteCond   %{REMOTE_ADDR}   !^192\.168\.1\.7$  [NC]
RewriteCond   %{REMOTE_ADDR}   !^192\.168\.1\.8$  [NC]
RewriteCond   %{REMOTE_ADDR}   !^192\.168\.1\.9$  [NC]
RewriteCond   %{REMOTE_ADDR}   ^192\.168\.1\.5$  [NC]
</Directory>
DATA

OUTPUT

RewiteEngine On
RewriteCond   %{REMOTE_ADDR}   !^192\.168\.1\.10$  [NC]
RewriteCond   %{REMOTE_ADDR}   !^192\.168\.1\.11$  [NC]
RewriteCond   %{REMOTE_ADDR}   !^192\.168\.1\.12$  [NC]
RewriteCond   %{REMOTE_ADDR}   !^192\.168\.1\.13$  [NC]
RewriteCond   %{REMOTE_ADDR}   !^192\.168\.1\.14$  [NC]
RewriteCond   %{REMOTE_ADDR}   !^192\.168\.1\.15$  [NC]
RewriteCond   %{REMOTE_ADDR}   !^192\.168\.1\.16$  [NC]
RewriteCond   %{REMOTE_ADDR}   !^192\.168\.1\.17$  [NC]
RewriteCond   %{REMOTE_ADDR}   !^192\.168\.1\.18$  [NC]
RewriteCond   %{REMOTE_ADDR}   !^192\.168\.1\.19$  [NC]
RewriteCond   %{REMOTE_ADDR}   !^192\.168\.1\.20$  [NC]
RewriteCond   %{REMOTE_ADDR}   !^192\.168\.1\.21$  [NC]
RewriteCond   %{REMOTE_ADDR}   !^192\.168\.1\.22$  [NC]
RewriteCond   %{REMOTE_ADDR}   !^192\.168\.1\.23$  [NC]
RewriteCond   %{REMOTE_ADDR}   !^192\.168\.1\.24$  [NC]
RewriteCond   %{REMOTE_ADDR}   !^192\.168\.1\.25$  [NC]
RewriteCond   %{REMOTE_ADDR}   !^192\.168\.1\.26$  [NC]
RewriteCond   %{REMOTE_ADDR}   !^192\.168\.1\.27$  [NC]
RewriteCond   %{REMOTE_ADDR}   !^192\.168\.1\.28$  [NC]
RewriteCond   %{REMOTE_ADDR}   !^192\.168\.1\.29$  [NC]
RewriteCond   %{REMOTE_ADDR}   !^192\.168\.1\.30$  [NC]
RewriteCond   %{REMOTE_ADDR}   ^192\.168\.1\.5$  [NC]
</Directory>
share|improve this answer
    
good one what if we want to replace \.1\.7,\.1\.8 and \.1\.9 by \.1\.10 and \.1\.11 –  Networker Aug 4 at 19:26
    
@Networker - if you modify it just a little bit to make the addresss more generic - slightly - like /\(\^[^$]*\.\)[0-9]*/ <that, then you can just keep on printing out new lines like s//!\110/p;s//\111/p;g and so on. –  mikeserv Aug 4 at 19:32
    
can you update your answer with new updates :) –  Networker Aug 4 at 19:38
    
@Networker - mission accomplished. –  mikeserv Aug 4 at 20:04
    
@mikesev, amazing answer and amazing explanation thanks :) –  Networker Aug 4 at 20:07

A way with gawk:

awk '{gsub(/\.[7-9]\$/,"\.10$")}!a[$0]++' test
share|improve this answer
    
Thanks it worked, but can you explain how the command worked and how can I make the change inline (inside the file). –  Networker Aug 4 at 17:09
    
If should be awk '{gsub(/\\\.[7-9]/, "\\.10")} !a[$0]++' file –  Srini Aug 6 at 8:57
    
@Srini no it shouldn't –  Jidder Aug 6 at 9:42
    
your code will remove '.' and it will replace even if there is no '\' before the number... echo '!^192\.168\.1\.7$ !^192\.168\.1.7$' | awk '{gsub(/\.[7-9]\$/,"10$")}!a[$0]++' will give you !^192\.168\.1\10$ !^192\.168\.110$ –  Srini Aug 7 at 3:31
    
It's not supposed to check for a \ before a number. It did leave a . out though so i've changed that –  Jidder Aug 7 at 7:05

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.