I made a website in php4 that I want to swtich over for my database, I'm a linux newb, I just thought I would write a simple sed script to change the username and password used in mysql_connect:

#!/bin/bash
for f in *
do
sed 's/mysql_connect(\'localhost\',\'user1\',\'pass1\')/mysql_connect(\'localhost\',\'user2\',\'pass2\')/' <$f >$f
done
exit 0

error:

./change: line 4: syntax error near unexpected token `)'

Also, someone mentioned that the script doesn't end? so I added exit 0, Ive only tried scripting once, over a year ago I don't remember ever doing that so if someone could elaborate that would be helpful.

Dani AI

Generated

Good progress, — you ran into two very common pitfalls: shell quoting and redirecting output back into the same file.

The syntax error came from how single quotes were used. In POSIX shells you cannot escape a single quote inside a single-quoted string, so the shell saw the sed expression as an unterminated/broken quoted string and choked on the next characters (hence the unexpected )). Also, using > $f while also reading from $f will usually truncate the file before the command runs. Fix both by quoting the sed expression so the embedded single quotes are literal and by writing to a temporary file (or using in-place editing tools).

A safe pattern that avoids both problems is to use an alternate delimiter and a temp file, then move the result back into place:

for f in *; do
  sed "s@mysql_connect('localhost','user1','pass1')@mysql_connect('localhost','user2','pass2')@g" "$f" > "$f.tmp" && mv "$f.tmp" "$f"
done

To prevent the script from editing itself (your observed “oops”), compare filenames against the running script’s basename and skip non-regular files and directories:

scriptname=$(basename "$0")
[ "$f" = "$scriptname" ] && continue
[ ! -f "$f" ] && continue

Extra tips: quote all variable expansions (e.g. "$f"), test on a single file first, keep backups (mv file backup/ or sed -i.bak), and note portability: GNU sed -i differs from BSD/macOS sed -i (macOS requires a backup suffix or ''). If filenames may contain spaces or many files are involved, prefer find -print0 | xargs -0 or while IFS= read -r -d '' file; do …; done to avoid word-splitting.

I wrote another script which I thnk comes closer to what I really wanted:

#!/bin/bash
for f in 'onestopshop/*'
do
echo "" | cat > tmp.txt
while read line
do
s=""
sed 's/user1/user2/'  < $line | sed 's/pass1/pass2/' > $s
if((${#s})>1)
do
cat $s >> tmp.txt
else
cat $line >> tmp.txt
fi
done < $f
cp ((onestopshop/$f)) tmp.txt
done
exit 0

where it checks for a pattern match before writing the line to tmp.txt, and writing the modified line if a match was found.

Now this is the final working solution:

#!/bin/bash
if [ ! -e backup ]
then
    mkdir backup
fi
for f in *
do
    if [ "$f" != "change" ]
    then
        if [ ! -d $f ]
        then
            cp $f backup/$f
            sed -i 's/user1/user2/g' $f
            sed -i 's/pass1/pass2/g' $f
        fi
    fi
done
exit 0

Except the if statement [ "$f" != "change" ] didn't protect the script from being changed itself. oops.

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.