Try:
dirs=( example/*/ )
mkdir -v "${dirs[@]/%/a}"
dirs=( example/*/ )
creates an array of all the subdirectories of example
( (example/dir1/ example/dir2/ ...)
).
"${dirs[@]/%/a}"
expands to a list containing all the elements of dirs
with an a
appended to each of them ( (example/dir1/a example/dir2/a ...)
).
If you have a very large number of subdirectories the mkdir
in the code above may fail with an "Argument list too long" error. See Argument list too long error for rm, cp, mv commands.
One way to avoid the problem is to pass a NUL-terminated list of the directories to be created to xargs -0
:
dirs=( example/*/ )
printf '%s\0' "${dirs[@]/%/a}" | xargs -0 mkdir -v
That will, if necessary, run multiple mkdir
commands, each with an argument list that does not exceed the limit.
However, if the number of directories is that large you may run into performance problems due to Bash (unnecessarily, but unavoidably) sorting the list produced by example/*/
). In that case it would be better to use find
. One way to do it is:
find example -maxdepth 1 -mindepth 1 -type d -printf '%p/a\0' | xargs -0 mkdir -v
find
has built-in support for xargs
-like behaviour with -exec ... +
. However, it's a bit fiddly to use in this case. The best I can come up with in a hurry is:
find example -maxdepth 1 -mindepth 1 -type d \
-exec bash -c 'mkdir -v "${@/%//a}"' bash {} +
Since it adds /a
to all of the arguments passed to bash
by find
before running mkdir
on them, it may encounter an "Argument list too long" error anyway. I'll leave it here because it illustrates a sometimes-useful technique, but I recommend against using it.