1

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

Jason
  • 361
  • 6
  • 19
  • This is not a site to give programming advice. So just the hint: Perl can do it! And there is more than one solution for that. – mailq Oct 16 '11 at 23:23
  • 1
    true, but this is a typical sysadmin task, though? I wouldn't flag this for moving, but that may just be me. – Kvisle Oct 16 '11 at 23:50

2 Answers2

2

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
Kvisle
  • 4,113
  • 23
  • 25
  • +1 for effort so far, this is definitely leading me in the right direction. This post has brought up some other concerns I have just thought about. Will the shell script only create a .old file if the searched line exists? or will it recreate all .htaccess files regardless of whether they have that line in it or not... – Jason Oct 17 '11 at 01:12
  • Also, the echo command didn't quite work, `cat list.txt /home/*/site/assets/.htaccess` – Jason Oct 17 '11 at 01:13
  • I suspect the echo command didn't work because you have several levels of directories. I should also note that you need to use bash. To answer the ".old"-file question; yes - it will only do it if the file exists. It executes the three lines once for each found file. – Kvisle Oct 17 '11 at 05:37
2

You can use sed to insert the line above the matched pattern and make backups as you go.

for file in  $( find /home -name .htaccess | grep /site/assets/sym); do
    sed -i.bak '/RewriteRule \^(.\*)\$ \/site\/assets\/sym\/\$1 \[L,NS\]/i RewriteCond %{REQUEST_URI} !^/site/assets/sym' "$file"
done
  • sed -i.bak will edit the files in place and create a .bak file for each one
  • /PATTERN/i another pattern - match PATTERN and insert another pattern before it.
user9517
  • 114,104
  • 20
  • 206
  • 289