cd into all directories, execute command on files in that directory, and return to previous current directory
for d in ./*/ ; do (cd "$d" && somecommand); done
The best way is to not use cd
at all:
find some/dir -type f -execdir somecommand {} \;
execdir
is like exec
, but the working directory is different:
-execdir command {} [;|+]
Like -exec, but the specified command is run from the
subdirectory containing the matched file, which is not normally
the directory in which you started find. This a much more
secure method for invoking commands, as it avoids race
conditions during resolution of the paths to the matched files.
It is not POSIX.
cd -P .
for dir in ./*/
do cd -P "$dir" ||continue
printf %s\\n "$PWD" >&2
command && cd "$OLDPWD" ||
! break; done || ! cd - >&2
The above command doesn't need to do any subshells - it just tracks its progress in the current shell by alternating $OLDPWD
and $PWD
. When you cd -
the shell exchanges the value of these two variables, basically, as it changes directories. It also prints the name for each directory as it works there to stderr.
I just had a second look at it and decided I could do a better job with error handling. It will skip a dir into which it cannot cd
- and cd
will print a message about why to stderr - and it will break
w/ a non-zero exit code if your command
does not execute successfully or if running command
somehow affects its ability to return to your original directory - $OLDPWD
. In that case it also does a cd -
last - and writes the resulting current working directory name to stderr.