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.