XaxD
XaxD

Reputation: 1538

How to loop a shell script across a specific file in all directories?

Shell Scripting sed Errors:

Cannot view /home/xx/htdocs/*/modules/forms/int.php

/bin/rm: cannot remove `/home/xx/htdocs/tmp.26758': No such file or directory

I am getting an error in my shell script. I am not sure if this for loop will work, it is intended to climb a large directory tree of PHP files and prepend a functions in every int.php file with a little validation. Don't ask me why this wasn't centralized/OO but it wasn't. I copied the script as best I could from here: http://www.cyberciti.biz/faq/unix-linux-replace-string-words-in-many-files/

#!/bin/bash
OLD="public function displayFunction(\$int)\n{"
NEW="public function displayFunction(\$int)\n{if(empty(\$int) || !is_numeric(\$int)){return '<p>Invalid ID.</p>';}"
DPATH="/home/xx/htdocs/*/modules/forms/int.php"
BPATH="/home/xx/htdocs/BAK/"
TFILE="/home/xx/htdocs/tmp.$$"
[ ! -d $BPATH ] && mkdir -p $BPATH || :
for f in $DPATH
do 
 if [ -f $f -a -r $f ]; then
   /bin/cp -f $f $BPATH
   sed "s/$OLD/$NEW/g" "$f" > $TFILE && mv $TFILE "$f"
 else
  echo "Error: Cannot view  ${f}"
 fi
done
/bin/rm $TFILE

Do wildcards like this even work? Can I check in every subdirectory across a tree like this? Do I need to precode an array and loop over that? How would I go about doing this?

Also is, the $ in the PHP code breaking the script at all?

I am terribly confused.

Upvotes: 0

Views: 208

Answers (1)

Camusensei
Camusensei

Reputation: 1563

Problems in your code

  • You cannot use sed to replace multiple lines this way.
  • you are using / in OLD which is used in a s/// sed command. This won't work
  • [ ! -d $BPATH ] && mkdir -p $BPATH || : is horrible. use mkdir -p "$bpath" 2>/dev/null
  • Yes, wildcards like this will work but only because your string has no spaces
  • Doube-quote your variables, or your code will be very dangerous
  • Single quote your strings or you won't understand what you are escaping
  • Do not use capital variable names, you could accidentally replace a bash inner variable
  • do not rm a file that does not exist
  • Your backups will be overwritten as all files are named int.php

Assuming you are using GNU sed, I'm not used to other sed flavors. If you are not using GNU sed, replacing the \n with a newline (inside the string) should work.

Fixed Code

#!/usr/bin/env bash
old='public function displayFunction(\$int)\n{'
old=${old//,/\\,} # escaping eventual commas
# the \$ is for escaping the sed-special meaning of $ in the search field
new='public function displayFunction($int)\n{if(empty($int) || !is_numeric($int)){return "<p>Invalid ID.</p>";}\n'
new=${new//,/\\,} # escaping eventual commas
dpath='/home/xx/htdocs/*/modules/forms/int.php'
for f in $dpath; do 
    [ -r "$f" ]; then
        sed -i.bak ':a;N;$!ba;'"s,$old,$new,g" "$f"
    else
       echo "Error: Cannot view  $f" >&2
    fi
done

Links

Upvotes: 1

Related Questions