3

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?

1
  • 1
    if you're using find use find ... -delete instead. Piping to rm makes no sense
    – CervEd
    Apr 13 at 21:01
6
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.

8
  • what does + do in : find . -type f -name '*.scala' -exec rm {} + Apr 5 '18 at 18:52
  • @linuxuser It means that as many as possible files will be given to rm at once. If I had used -exec rm {} \;, I would have called rm once for each individual file. With +, the operation will be quicker since there will be less calls to rm.
    – Kusalananda
    Apr 5 '18 at 19:06
  • Does it mean if find returns 5 files, by default xargs will execute the given command 5 times. But with + xargs will execute the given command only once Apr 7 '18 at 5:35
  • 1
    @linuxuser -exec rm {} + would execute rm once with five files, while -exec rm {} \; would execute rm five times with one file each time.
    – Kusalananda
    Apr 7 '18 at 6:18
  • 1
    @linuxuser Yes, it's a feature of find and its -exec, not of rm. It would work similarly with any utility executed through -exec. Note that if you use -exec utility {} +, the {} must always come last before the + and the utility must support being called with multiple filenames.
    – Kusalananda
    Apr 7 '18 at 6:22

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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