Linux – Search and Replace in .htaccess files in linux

linuxsearch-and-replace

I need to add this line to every .htaccess file that is located in a /home/*/site/assets/.htaccess
where * can be any amount of directories deep

I need to fine this text

RewriteRule ^(.*)$ /site/assets/sym/$1 [L,NS]

and add a line above it, or replace it with this

RewriteCond %{REQUEST_URI} !^/site/assets/sym
RewriteRule ^(.*)$ /site/assets/sym/$1 [L,NS]

I've looked online at this site but I am unclear how to deal with

  1. generating a list of the files I want to edit (so find all files that match this path: /home/*/site/assets/.htaccess)
  2. Adding line breaks in the replace text

Can anyone suggest a resource that will clearly explain it, or fail that, let me know if I am looking at the correct tools for this job?

My OS is Cent OS 5.5, i'm running a LAMP server if that makes much difference, apache 2.

Thanks

Best Answer

You've chosen an excellent set of tools for the job!

Generating a list of files you want to edit is very simple - I'm here assuming you're using a shell which will expand the output of matching filenames, such as bash, or dash:

echo /home/*/site/assets/.htaccess > list.txt

However, if * can mean more than 1 level of directories, I would go with this:

find -name '.htaccess' /home | grep '/site/assets/sym' > list.txt

Your shell will expand the expression into a list, and redirect the output to list.txt. One file for each line.

You can also search for files named .htaccess with find - to see if there's anyone that you've missed, like this:

find -name '.htaccess' /home

Adding line breaks in replace text - this depends a bit on your editor. Line breaks are usually represented as \n

What you want to do, can probably be achieved with a small shell-script - when for variable in expression; do .... done is used, it will execute the lines in between do/done once for each word in expression. NOTE: This can backfire if the paths contain spaces.

for file in /home/*/site/assets/.htaccess; do
    sed 's/RewriteRule \^(.\*)\$ \/site\/assets\/sym\/\$1 \[L,NS\]/RewriteCond %{REQUEST_URI} !^\/site\/assets\/sym\nRewriteRule \^(.\*)\$ \/site\/assets\/sym\/\$1 \[L,NS\]/g' $file > $file.new
    mv $file $file.old
    mv $file.new $file
done

(This will leave a file named .htaccess.old in its spot.)

Rewritten for alternate list-gathering-approach:

for file in $(find -name '.htaccess' /home | grep '/site/assets/sym'); do
    sed 's/RewriteRule \^(.\*)\$ \/site\/assets\/sym\/\$1 \[L,NS\]/RewriteCond %{REQUEST_URI} !^\/site\/assets\/sym\nRewriteRule \^(.\*)\$ \/site\/assets\/sym\/\$1 \[L,NS\]/g' $file > $file.new
    mv $file $file.old
    mv $file.new $file
done

Or, in one line, without taking a backup:

for file in /home/*/site/assets/.htaccess; do sed -i 's/RewriteRule \^(.\*)\$ \/site\/assets\/sym\/\$1 \[L,NS\]/RewriteCond %{REQUEST_URI} !^\/site\/assets\/sym\nRewriteRule \^(.\*)\$ \/site\/assets\/sym\/\$1 \[L,NS\]/g' $file; done