On my Ubuntu system, I commonly need to do a 'Deep Replace' in file contents, the file name and directory name. For example when copying source code as a template for another application.
I've put together a function in ~/.bashrc
which works, but fails if the find or replace string has white space in it. I believe this is due to the sed command not accepting white space in the script as is, and the cd to the path variable also fails where the path includes white space.
The arguments are ($1) directory, ($2) find text, ($3) replace text.
Is it possible to improve this script so the arguments can all include white space?
deepreplace() {
if [ -z "$1" ] || [ -z "$2" ] || [ -z "$3" ]
then
echo "A parameter is missing"
else
cd $1
vfind=$2
vreplace=$3
# Replace the string in file
find . -type f -exec sed -i "s/$vfind/$vreplace/g" {} +
# Replace the string in file names, then directories
find . -type d -name "*$vfind*" | while read f; do mv $f $(echo $f | sed "s/$vfind/$vreplace/g"); done
find . -type f -name "*$vfind*" | while read f; do mv $f $(echo $f | sed "s/$vfind/$vreplace/g"); done
fi
}
cd
isn't needed sincefind
can take$1
as the directory to search in, it doesn't need to use.
:find "/some/path" -name foo
works fine. As for GNU find, I don't know if it's different :) That's why I asked you to tell us what OS you are using. The defaultfind
on Linux systems is usually GNUfind
, but macOS and other UNIX systems have different implementations. So either please tell us your OS or checkman find
and see if yourfind
has the-print0
or-printf
options. – terdon Jun 28 '22 at 09:49vfind=foo
andvreplace=bar
and you have a directory calledfoo
which is a subdirectory of another called foo (/whatever/foo/something/foo
). Do we need to be able to handle such cases? – terdon Jun 28 '22 at 13:19-exec
(or-execdir
) option instead of piping into a shell while-read loop. If necessary, you can run shell code withsh -c "...shell code here..." find-sh {} +
from-exec
, or write a standalone shell script and run that fromfind ... -exec
. If you have the perl rename utility installed, you could run something likefind . -name "*$vfind*" -exec rename "s/$vfind/$vreplace/g" {} +
(this will rename both directories AND regular files). – cas Jun 29 '22 at 02:28