Why can't xargs delete directories with spaces in their names, and how to fix that?

76 find . -type d |xargs  rm -rf
 77 rm -rf fire\ hydrant/
 78 rm -rf wine\ glass/
 79 rm -rf tennis\ racket/
 80 rm -rf traffic\ light/
 81 rm -rf parking\ meter/
 82 rm -rf teddy\ bear/
 83 rm -rf sports\ ball/
 84 rm -rf cell\ phone/
 85 rm -rf stop\ sign/
 86 rm -rf dining\ table/
 87 rm -rf potted\ plant/

marked as duplicate by Anwar, Eric Carvalho, WinEunuuchs2Unix, TheWanderer, andrew.46 Oct 28 '16 at 8:16

This question has been asked before and already has an answer. If those answers do not fully address your question, please ask a new question.

  • Why not use find's implemented -delete option? – Fiximan Oct 26 '16 at 21:28
  • 1
    I didn't know avout it – Mona Jalal Oct 26 '16 at 21:29
  • 3
    In that case: be sure to put it at the end! find will execute from left to right, so a -delete placed too early will result in too many files being deleted. – Fiximan Oct 26 '16 at 21:31
  • 1
    Also see: mywiki.wooledge.org/ParsingLs – muru Oct 27 '16 at 3:43

Fix it using -print0 in find and xargs -0 in xargs to tell both commands to use the NULL character as a separator instead of space:

find . -type d -print0 | xargs -0 rm -rf

Here's a nice explanation of why it breaks and how this fix works from The Linux Command Line by William E. Shotts Jr.

Dealing With Funny Filenames

Unix-like systems allow embedded spaces (and even newlines!) in filenames. This causes problems for programs like xargs that construct argument lists for other programs. An embedded space will be treated as a delimiter, and the resulting command will interpret each space-separated word as a separate argument. To overcome this, find and xarg allow the optional use of a null character as argument separator. A null character is defined in ASCII as the character represented by the number zero (as opposed to, for example, the space character, which is defined in ASCII as the character represented by the number 32). The find command provides the action -print0, which produces null-separated output, and the xargs command has the --null option, which accepts null separated input. Here’s an example:

find ~ -iname '*.jpg' -print0 | xargs --null ls -l

Using this technique, we can ensure that all files, even those containing embedded spaces in their names, are handled correctly.

(-0 is the short version of the --null option)

You don't need xargs, find itself can do it robustly with handling:

  • any kind of possible filenames

  • without triggering ARG_MAX

If the directories are empty, use -delete action:

find . -type d -delete

If not empty, use rm -r in the -exec action:

find . -type d -exec rm -r {} +

If you insist on using xargs, for any directory names without newline in their names you can use newline as the delimiter of incoming arguments:

find . -type d | xargs -d $'\n' rm -r

Best way, get files NUL separated and deal with it with -0 option of xargs:

find . -type d -name 'foo bar*' -print0 | xargs -0 rm -r

For all the rm -r used, add -f i.e. do rm -rf if needed.

  • «without triggering ARG_MAX» → can this be solved using xargs -n [something] or is it a limitation of xargs? Besides, while this specific case can be done with find, it wouldn't work for e.g. a list of file names in a file or something else entirely. xargs is more general than find. – Andrea Lazzarotto Oct 26 '16 at 22:43
  • 2
    @AndreaLazzarotto xargs also handles ARG_MAX. It's just that as you're already using find, there's no need to spawn an extra process, and of course an anonymous pipe when find can do the needful alone. – heemayl Oct 26 '16 at 23:21
  • Oooh! -exec + is new (well, some time in the previous 20 years :-) That's useful. – Martin Bonner Oct 27 '16 at 8:04
  • xargs is more efficient. -exec creates a subprocess for each file, while xargs baches them. – paj28 Oct 27 '16 at 11:32
  • 3
    @paj28 No, you are referring to -exec ... {} \;, here I've used -exec ... {} + (note the + instead of \;) which takes as many files so as the ARG_MAX is not triggered. – heemayl Oct 27 '16 at 11:45

To specifically delete all subdirectories having spaces in their name, the simplest command would be :

find . -type d -name "* *" -exec rm -rf {} +

This is the same approach as the one heemayl already suggested, the only difference being the -name filtering.

Not the answer you're looking for? Browse other questions tagged or ask your own question.