xargs with rm + filename containing spaces

7,643
xargs -d "\n" -I {} rm \"{}\"

This assumes GNU coreutils' version of xargs that supports the -d option for specifying the delimiter.

This will not work together with your find command because it adds double quotes to the pathnames found by find. This means that instead of ./somedir/file.scala, the call to rm is done with the literal pathname "./somedir/file.scala".

Example:

$ touch hello
$ touch '"hello"'
$ ls
"hello" hello
$ echo hello | xargs -d "\n" -I {} rm \"{}\"
$ ls
hello

It works when you pipe the generated commands to bash because bash does quote removal.

It would probably also have worked if you didn't go through the extra effort to add the quotes in the first place:

xargs -d "\n" -I {} rm {}

To delete your files properly, use

find . -type f -name '*.scala' -delete

or, if you still want to use xargs:

find . -type f -name '*.scala' -print0 | xargs -0 rm

which passes the pathnames between find and xargs as a nul-delimited list. Nul (\0) is the only character that is not allowed in a pathname on Unix systems. Filenames can additionally not contain /, but newlines are allowed.

A third option would be to call rm directly from find:

find . -type f -name '*.scala' -exec rm {} +

Note that {} does not need to be (and should not be) quoted as find knows perfectly well how to pass pathnames with spaces (or newlines or whatever it may be) to the named utility.

Share:
7,643

Related videos on Youtube

LoveWithMaths
Author by

LoveWithMaths

Updated on September 18, 2022

Comments

  • LoveWithMaths
    LoveWithMaths over 1 year

    I am writing a simple programs which deletes all the fetched files. Files can contain spaces so I have added quotations as seen below

    find -name "*.scala" | xargs -d "\n" -I {} rm \"{}\"
    

    The above fails with error : cannot remove, no such file or dir. But if I list the same files they are there. Also if I do below and use bash to execute it; it works

    find -name "*.scala" | xargs -d "\n" -I {} echo rm \"{}\" | bash
    

    Can someone please explain why 1st scenario din't worked?

    • CervEd
      CervEd about 3 years
      if you're using find use find ... -delete instead. Piping to rm makes no sense
  • LoveWithMaths
    LoveWithMaths about 6 years
    what does + do in : find . -type f -name '*.scala' -exec rm {} +
  • Kusalananda
    Kusalananda about 6 years
    @linuxuser -exec rm {} + would execute rm once with five files, while -exec rm {} \; would execute rm five times with one file each time.
  • LoveWithMaths
    LoveWithMaths about 6 years
    but the above definition is not limited to rm; its how exec argument will work for any command.
  • Kusalananda
    Kusalananda about 6 years
    @linuxuser -exec mv {} /destination + for example. With GNU mv, that may be written as -exec mv -t /destination {} + instead.