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 Commented Apr 13, 2021 at 21:01

1 Answer 1

11
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
  • 2
    what does + do in : find . -type f -name '*.scala' -exec rm {} + Commented Apr 5, 2018 at 18:52
  • 1
    @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. Commented Apr 5, 2018 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 Commented Apr 7, 2018 at 5:35
  • 2
    @linuxuser -exec rm {} + would execute rm once with five files, while -exec rm {} \; would execute rm five times with one file each time. Commented Apr 7, 2018 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. Commented Apr 7, 2018 at 6:22

You must log in to answer this question.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.