for loop in folders with \n character in their names
Solution 1:
You've only single command there, so it's sufficient to call find
with -exec
flag calling rmdir
:
find -depth -type d -exec rmdir {} \;
Or use the -delete
option as in find -type d -delete
, but it won't work with non-empty directories. For that you will also need -empty
flag. Note also, -delete
implies -depth
so that may be skipped. Thus another viable alternative that keeps everything as one process:
find -type d -empty -delete
If the directory not empty, use rm -rf {} \;
. To isolate only directories with \n
in filename we can combine bash's ANSI-C quoting $'...'
with -name
opption:
find -type d -name $'*\n*' -empty -delete
POSIX-ly, we could handle it this way:
find -depth -type d -name "$(printf '*\n*' )" -exec rmdir {} \;
It is worth mentioning that if your goal is removal of directories, then -delete
is sufficient, however if you want to execute a command on directory then -exec
is most appropriate.
See also
- How to delete directories based on
find
output? - find -delete does not delete non-empty directories
Solution 2:
You could use shell globs instead of find
:
for d in */ ; do
rmdir "$d"
done
The shell glob */
matches all folders in the current directory. This for-loop construction takes care of correct word splitting automatically.
Note that depending on your shell options, this might ignore hidden folders (name starting with a .). That behaviour can be changed to match all files for the current session using the command shopt -s dotglob
.
Also don't forget to always quote your variables.
Solution 3:
Both answers written so far call rmdir
once per directory, but as rmdir
can take multiple arguments I wonder: Isn’t there a more efficient way?
One could simply do
rmdir */
and that’s definitely the easiest and most efficient way, but it may throw an error in the case of many directories (see What is the maximum length of command line arguments in gnome-terminal?). If you want this approach to work recursively, enable the globstar
shell option with shopt -s globstar
and use **/*/
instead of */
.
With GNU find
(and if we don’t just want to use -delete
), we could do
find -depth -type d -exec rmdir {} +
which builts the command line “in much the same way that xargs
builds its command lines” (man find
). Substitute -depth
for -maxdepth 1
if you don’t want it to work recursively.
A third and IMO brilliant way is explained by steeldriver in this answer:
printf '%s\0' */ | xargs -0 rmdir
This uses the shell builtin printf
to build a zero-delimited argument list, this list is then piped to xargs
which calls rmdir
exactly as often as necessary. You can make it work recursively with shopt -s globstar
and **/*/
instead of */
as above.