Reputation: 321
I found this answer to my question which uses the following code to remove words from file names using sed
:
for fyle in $(find . -name "*.*")
do
mv -i $fyle `echo $fyle | sed -e 's/FOO//gI' -e 's/BANG//gI' `
done
But on my mac it chokes on filenames whose paths have spaces.
I tried to fix it by use of double quotes, but couldn't get it to work: the variable fyle now includes the entire list of files, not one at a time.
Because the original poster seemed happy with the code, maybe my problem is because of my OSX flavour of bash?
How can I modify the code above to work well?
Upvotes: 0
Views: 111
Reputation: 46866
As others have said, quotes are your friends.
But since you're using bash, you don't really need to use sed just to remove strings from filenames. Something like this might work, using parameter expansion:
find . -name '*.*' -exec bash -c 'out="${1//FOO/}; out="${out//BANG/}; mv -v "$1" "$out"' -- {} \;
But even find
is unnecessary in this case, so you can avoid subshells entirely:
shopt -s globstar
for f in **/*FOO*.* **/*BANG*.*; do
out=${f//FOO/}
out=${out//BANG/}
mv -v "$f" "$out"
done
This of course assumes that the keywords you're searching for are before a dot in the filename. It also assumes that you're running bash v4, for globstar
.
Upvotes: 4
Reputation: 42712
That seems very complicated. Will this work? Uses Bash's built-in string substitution and file globbing to replace bar
with baz
:
for i in *.txt; do mv "$i" "${i/bar/baz}"; done
Here it is in action:
mike ~/foobar $ touch "foo bar baz.txt"
mike ~/foobar $ touch "foobar.txt"
mike ~/foobar $ touch "carbar.txt"
mike ~/foobar $ for i in *.txt; do mv "$i" "${i/bar/baz}"; done
mike ~/foobar $ ls
carbaz.txt foo baz baz.txt foobaz.txt
mike ~/foobar $
As chepner mentioned below, this will not recurse into directories.
Upvotes: 0
Reputation: 785611
You should not iterate the find
command's output in for
loop otherwise shell expansion for filenames with space/newline will occur and your results will be wrong.
Use -print0
option in find
and iterate using process substitution in a while read
loop with null IFS
.
while IFS= read -rd '' fyle; do
mv -i "$fyle" $(sed 's/FOO//gI; s/BANG//gI' <<< "$fyle")
done < <(find . -type f -name "*.*")
Upvotes: 4
Reputation: 147
I believe you need to double-quote the variable reference in the mv
command to account for the spaces...
mv -i "$fyle" ...
Upvotes: 2