If I got it right, you have files and directories like this:
$ mkdir dir{1,2,3} ; touch file{1,2,3} .file{1,2,3}
$ ls -A
.file1 .file2 .file3 dir1 dir2 dir3 file1 file2 file3
and want to rename the dirs to _dir1
, _dir2
, _dir3
?
That find
/printf mv
looks doable. Let's see what it prints:
$ find . -type d -name '*' -printf "mv \"%h/%f\" \"%h/_%f\"\n"
mv "./." "./_."
mv "./dir2" "./_dir2"
mv "./dir3" "./_dir3"
mv "./dir1" "./_dir1"
That first command will drop an error, since the "dot" is special and you can't rename it. But the others should be ok, and should rename the directories as you wanted:
$ find . -type d -name '*' -printf "mv \"%h/%f\" \"%h/_%f\"\n" | sh
mv: cannot move ‘./.’ to ‘./_.’: Device or resource busy
$ ls -d _dir*
_dir1 _dir2 _dir3
But piping commands to a shell is a bit ugly, and if the file names are strange enough, the results will be surprising (e.g. if they contain $
signs which will trigger variable or command substitution in the shell).
If the files are all on one level, then this should do:
for x in * ; do [ -d "$x" ] && mv "$x" "_$x" ; done
(Though if _$x
exists already, $x
will be moved into it.)
If you want to include directories whose names start with a dot, use shopt -s dotglob
beforehand.
This is close, too:
find . -type d -exec rename 's/^/_/' {} \;
But since find
gives rename
the paths starting with ./
, we need to take that into account. On one level only, this should do (changes the leading ./
to ./_
):
find . -type d -exec rename 's,^./,./_,' {} \;
To get the directories on all levels, find -execdir
may be easiest to use. It runs the command in the directory of the file. We need -depth
to handle the renames in the correct order.
find . -depth -type d -execdir rename 's,^./,./_,' {} \;
Maybe add ! -name .
, too. e.g.
$ mkdir foo foo/dir1 foo/dir2
$ find . -depth \! -name . -type d -execdir rename 's,^./,./_,' {} \;
$ ls _foo
_dir1 _dir2
./
to beginning.. so if your rename is perl based, tryrename -n 's|^.*/\K|_|'
and once you are okay with it, remove the-n
option.. also, can use+
instead of\;
similar answer: unix.stackexchange.com/questions/310256/…*/
glob e.g.for d in */; do echo mv -- "$d" "_$d"; done