I have a directory with some subdirectories with filenames and directorynames that contain some dots:
$ ls -R
.:
dir file.with.dots
./dir:
subdir.with.dots
./dir/subdir.with.dots:
other.file
I really struggle to catch all these files with find
because I don't want to rename the current folder .
and ..
itself.
I also read how to Replace dots with underscores in filenames, leaving extension intact, but that doesn't really fit here, because the main problem is the recursive selection of the files.
I tried to replace the dots with find
and tr
:
find $(pwd) -depth -name '*.*'|while read f; do mv -iv "$f" '"'$(echo $f|tr '.' '_')'"' ; done
but this would give errors if in both, the path to the file and the file itself, contains dots
How do I rename and replace all occurrences of a dot with an underscore?
Best Answer
With
zsh
:Otherwise, if you have access to
bash
(thoughksh93
orzsh
will do as well), you could always do:(though you'll miss the sanity checks done by
zmv
).Those (intentionally) don't rename hidden files.
The point is to process the list depth-first (which
zmv
does by default, and using-depth
infind
) and only rename the basename of the file.So that you do:
and then:
Also note that for the non-zmv solution, if you have a
a.b
file and aa_b
directory in the same directory, thenmv -- a.b a_b
will happily movea.b
intoa_b/
. To avoid that, if on a GNU system, you can add the-T
option tomv
.As I see you tried to edit the answer to use a
while read
loop.Note that you should generally avoid
while read
loops, even in this case where one command per line has to be run anyway. If you really want to use one, then doing it right is tricky and involves ksh/bash/zshisms:(you can replace
-exec printf '%s\0' {} +
with-print0
if your find supports it).You need:
-print0
/-exec printf '%s\0' {} +
as you can't rely on newline as the separator since newline is a valid character in a filename-d ''
(read
reads until NUL instead of NL)IFS=
(that is remove all the whitespace characters fromIFS
forread
as otherwise strips them from the end of the input record).-r
as otherwiseread
treats backslash as an escape character (for the field and record separator).mv
to be the terminal (for the answers to the-i
prompts), not the pipe fromfind
.