Your function were almost conform to your requirements, just missing a lot of quotes around variables and substitutions, that's why it did not resist to space in filenames.
- variables : "$1" "$2" "$f" etc.
- substitutions : "$( ... )"
Here is a first low touch review:
deepreplace() {
if [ -z "$1" ] || [ -z "$2" ] || [ -z "$3" ]
then
echo "A parameter is missing"
else
cd "$1" # quote missing
vfind="$2" # quote missing
vreplace="$3" # quote missing
# Replace the string in file contents
find . -type f -exec sed -i "s/$vfind/$vreplace/g" {} +
# Replace the string in directory names
find . -type d -name "*$vfind*" |
while read d ; do
mv "$d" "$(echo "$d" | sed "s/$vfind/$vreplace/g")"
done
# Replace the string in file names
find . -type f -name "*$vfind*" |
while read f; do
mv "$f" "$(echo "$f" | sed "s/$vfind/$vreplace/g")"
done
fi
}
next improvements:
- instead of
$(echo $v | sed s/x/y/g)
use the built-in${v//x/y}
example:mv "$f" "${f//$vfind/$vreplace}"
- you have a problem when the path is to be replaced at more than directory level; that's why you first target directories then files (and not files then directories)
- it's useless to perform
find
three times
Here is a pure bash new approach:
find . | while read p ; do
ddir="$(dirname "${p//$vfind/$vreplace}")"
obas="$(basename "$p")"
nbas="${obas//$vfind/$vreplace}"
# if object rename
[[ $obas != $nbas ]] && mv "$ddir/$obas" "$ddir/$nbas"
# if object is file, edit
[ -f "$ddir/$nbas" ] && sed -i "s/$vfind/$vreplace/g" "$ddir/$nbas"
done
find
natural output order make that directories are always renamed before their children, so that it is safe to rename only the basename element- all names may safely contain spaces
- only one
find
does the job at lower cost - you save dependencies to js