0

I'm trying to script a change to my apache config file (httpd.conf). I'm trying to match the following string:

# # DirectoryIndex: sets the file that Apache will serve if a directory 

And PREPEND the following text:

# # Allow server status reports generated by mod_status, # with the URL of http://servername/server-status # Change the ".example.com" to match your domain to enable. # <Location /server-status> SetHandler server-status Order deny,allow Deny from all Allow from localhost ip6-localhost 127.0.0.1 192.168.0.0/255.255.255.0 </Location> 

My understanding is that sed doesn't support multiple line matches, awk seems difficult to do multiple line matches. I'm trying to get perl to work with perl -0777 -pi -e but I can't seem to figure out a regular expression that matches the original pattern.

I'd prefer to do this as a one liner - not a script because i want it to be portable (i.e. copy and paste as needed).

Any perl regex experts out there that can help me devise a solution?

Many thanks in advance Brad

EDIT

The following works:

 sed -i -e ':begin;$!N;s/#\n# DirectoryIndex/#\n# Allow server status reports generated by mod_status,\n# with the URL of http:\/\/servername\/server-status\n# Change the ".example.com" to match your domain to enable.\n#\n<Location \/server-status>\n\tSetHandler server-status\n\tOrder deny,allow\n\tDeny from all\n\tAllow from localhost ip6-localhost 192\.168\.0\.0\/255\.255\.255\.0\n<\/Location>\n\n#\n\#DirectoryIndex/;tbegin;P;‌​D' /etc/httpd/conf/httpd.conf 

But there's no space between the # and DirectoryIndex.

However if I try to change it to:

sed -i -e ':begin;$!N;s/#\n# DirectoryIndex/#\n# Allow server status reports generated by mod_status,\n# with the URL of http:\/\/servername\/server-status\n# Change the ".example.com" to match your domain to enable.\n#\n<Location \/server-status>\n\tSetHandler server-status\n\tOrder deny,allow\n\tDeny from all\n\tAllow from localhost ip6-localhost 192\.168\.0\.0\/255\.255\.255\.0\n<\/Location>\n\n#\n\# DirectoryIndex/;tbegin;P;‌​D' /etc/httpd/conf/httpd.conf 

The sed command hangs and never finishes. I can't seem to figure out why?

The only difference is a space between # and DirectoryIndex.

10
  • It look like a Stack over flow question ? Commented Nov 25, 2015 at 17:36
  • You can use replace #\n# DirectoryIndex: sets the file that Apache will serve if a directory by this + new text, you don't need a reg exp for that | or you can get the line of this text and append after what you want. Commented Nov 25, 2015 at 17:37
  • Thanks i've flagged it and proposed it be migrated to stackoverflow. I wasn't sure weather to use stackoverflow, serverfault, or linux/unix site. Commented Nov 25, 2015 at 17:52
  • It's perfectly fine here. This is a sysadmin task. Commented Nov 25, 2015 at 17:54
  • @Froggiz - sed won't do multiline matches though. And trying to do what you propose with perl is failing: Commented Nov 25, 2015 at 18:10

2 Answers 2

2

With awk, how about:

  • store every line in a variable for "the previous line"
  • if the current line matches the second one you're looking for (DirectoryIndex), check the variable with the previous line
  • If they both match
    • print the bumpf
    • print the 'current line'
    • print the swallowed '#'
  • Else
    • print the current line
  • update the 'previous line' variable with the current line.

This should work for you because you don't strictly need to PREPEND the text - since both the text you're looking for and the text you're inserting start with # you can leave the original #, insert your text minus the first # line in the middle, then print the original second line, then print another # to be the one you didn't prepend.

You'll have to fill in the full text, but there's enough here to convince me it can work ;)

gawk "{if (a==\"#\" && /^# DirectoryIndex/) {print \"# Allow Server\n#With the URL\n#\"; print $0} else {print $0}} {a=$0}" httpd.conf > ?? 

(My double quote escapes are for Windows' command prompt. Adjust as necessary).

Edited quoting for bash:

gawk '{if (a=="#" && /^# DirectoryIndex/) {print "# Allow Server\n# With the URL\n#"; print $0} else {print $0}} {a=$0}' httpd.conf 
7
  • This just outputs a string of zeros for me: 0 0 0 0 0 0 Commented Nov 25, 2015 at 21:10
  • That's part of the "adjust the quoting for your shell" bit.... I've edited my answer with a different quoting, and it seems to work on bash like that. Commented Nov 25, 2015 at 21:18
  • I have this working sorta. When I run the gawk statement it empties my config file. Commented Nov 25, 2015 at 22:12
  • gawk '{if (a=="#" && /^# DirectoryIndex/) {print "# Allow server status reports generated by mod_status,\n# with the URL of servername/server-status\n# Change the \".example.com\" to match your domain to enable.\n#\n<Location /server-status>\n\tSetHandler server-status\n\tOrder deny,allow\n\tDeny from all\n\tAllow from localhost ip6-localhost 127.0.0.1 192.168.0.0/255.255.255.0\n</Location>\n\n#"; print $0} else {print $0}} {a=$0}' /etc/httpd/conf/httpd.conf > /etc/httpd/conf/httpd.conf Commented Nov 25, 2015 at 22:13
  • Maybe you can't read and write the same file at once - one of these stackoverflow.com/q/16529716/478656 answers could help? Commented Nov 25, 2015 at 22:17
2

You should try

perl -0777 -i.original -pe 's/#\n# DirectoryIndex: sets the file that Apache will serve if a directory/#\n# DirectoryIndex: sets the file that Apache will serve if a directory\n#\n# Allow server status reports generated by mod_status,\n# with the URL of http:\/\/servername\/server-status\n# Change the ".example.com" to match your domain to enable.\n#\n<Location \/server-status>\n SetHandler server-status\n Order deny,allow\n Deny from all\n Allow from localhost ip6-localhost 127.0.0.1 192.168.0.0\/255.255.255.0\n<\/Location>/igs' /etc/httpd/conf/httpd.conf 

Don't forget to escape your string replace (\/ for /) when you are using / delimiter in regexp tool

If you are running it through shell, you can do a script like that

#Set serach delimiter search='#\n# DirectoryIndex: sets the file that Apache will serve if a directory' #Set replace string from file replace=$search"\n"$(cat newConfFile) #Escape "/" char replace=${replace//\//\\\/ } #Launch the script perl -0777 -i.original -pe 's/${search}/${replace}/igs' /etc/httpd/conf/httpd.conf 

With newConfFile containt the virtual host configuration you want to add

This is a Bash Function to test if a function exist

#return 0 if command exist else return 1 canExec() { type "$1" &> /dev/null ; } 

for example canExec sed test if sed command exist on your system

9
  • This part is actually a block of text which I truncated: # # DirectoryIndex: sets the file that Apache will serve if a directory So really its: # # DirectoryIndex: sets the file that Apache will serve if a directory # More Stuff # And More So what the above does is sandwich it right in the middle of the statement: # # DirectoryIndex: sets the file that Apache will serve if a directory {Puts contents here} # More Stuff # And More Commented Nov 25, 2015 at 20:59
  • How you get the default string where to put your data after, can it be set as variable or even external file ? how you will launch your command, in a program ? Commented Nov 25, 2015 at 21:12
  • I'm looking to create a one-liner (mind you a very long one liner) which can be copied and pasted (as needed) into a bash prompt. Assuming the user has sed/awk/perl already installed. Commented Nov 25, 2015 at 21:14
  • I'm indifferent as to weather it uses sed or awk or perl - i have it ALMOST working in sed (per the comments in the original post) but the spacing isn't quite right and when I try and correct it sed hangs. Commented Nov 25, 2015 at 21:15
  • sed & hawk are almost all the time on any linux system, but perl need a package for it. If you need you can test if command exist in bash i addeded a func in my post Commented Nov 25, 2015 at 21:22

You must log in to answer this question.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.