How to quote arguments with xargs
Solution 1
As you're already using that non-standard 1M
, chances are your find
implementation also supports -delete
. So, simply use:
find . -type f -size +1M -delete
Where supported, that's by far the safest and most efficient.
If you insist on using xargs
and rm
with find
, just add -print0
in your command:
find . -type f -size +1M -print0 | xargs -r0 rm -f --
(-print0
and -0
are non-standard, but pretty common. -r
(to avoid running rm
at all if find
doesn't find anything) is less common, but if your xargs
doesn't support it, you can just omit it, as rm
with -f
won't complain if called without argument).
The standard syntax would be:
find . -type f -size +1048576c -exec rm -f -- {} +
Other way:
find . -type f -size +1M -execdir rm -f -- {} +
(that's safer than -exec
/xargs -0
and would work with very deep directory trees (where full file paths would end up larger than PATH_MAX
), but that's also non-standard, and runs at least one rm
for each directory that contains at least one big file, so would be less efficient).
From man find
on a GNU system:
-print0
True; print the full file name on the standard output, followed by a null character (instead of the newline character that
find
output. This option corresponds to the-0
option ofxargs
.
Solution 2
I had a similar requirement and ended up using the -I
switch to have a placeholder and I was able to quote it.
find . -size +1M | xargs -I {} rm "{}"
Solution 3
Option -0
of xargs
means that output from pipe is interpreted as null terminated items. In such case you also need to create input for the pipe with find ... -print0
.
Solution 4
Actually just reiterating an existing comment to the question so that it appears under answers, in my case I was using locate
to find filenames containing a certain string:
Ivan Zakharyaschev wrote: Use xargs -d$'\n'
to limit the delimiter to only new lines (and not spaces; this wouldn't process quotes etc. specially -- I've checked on a GNU system) -- the answer given in
stackoverflow.com/a/33528111/94687
So for example using Ivan's suggestion,
$ locate -i example_string | xargs -d$'\n' md5sum
Solution 5
Here is a simple way to do it that does not rely on special flags in find
. It works for any input into xargs
. Just use sed
to wrap each line in quotes.
find . -size +1M | sed 's/.*/"&"/' | xargs ls -l
You can replace ls -l
with rm
after you are satisfied it works.
Related videos on Youtube
Benny Abramovici
Developer who enjoys sharing knowledge. https://ksharma.dev Open source projects: Github
Updated on September 18, 2022Comments
-
Benny Abramovici over 1 year
Suppose that I want to delete all files in a folder that are greater than 1 MB.
$ find . -size +1M | xargs -0 rm
This will not delete files that have space in their names. So I want it to quote all arguments it sends to
rm
. Iffind
gives itSome report.docx
it should pass"Some report.docx"
torm
.How can I do that?
-
Marek Zakrzewski over 9 yearsYou should read this mywiki.wooledge.org/UsingFind?highlight=%28xargs%29 before doing anything with
xargs
. Also as the wiki suggests, don't usexargs
without passing the-print0
tofind
. -
Gilles 'SO- stop being evil' over 9 yearsMore generally, see Why does my shell script choke on whitespace or other special characters?
-
imz -- Ivan Zakharyaschev almost 7 yearsUse
xargs -d$'\n'
to limit the delimiter to only new lines (and not spaces; this wouldn't process quotes etc. specially -- I've checked on a GNU system) -- the answer given in stackoverflow.com/a/33528111/94687 -
Stéphane Chazelas about 3 years
-
Stéphane Chazelas about 3 yearsSee Search for text files where two different words exist (any order, any line) for the length you have to go to transform file paths into the format expected by
xargs
without the-0
option.
-
-
Benny Abramovici over 9 yearsThis solves the problem but actually quoting the arguments would be useful in other cases. So I'll hold on for other answers. +1 for a simple solution though.
-
Gilles 'SO- stop being evil' over 9 years@KshitizSharma No, you do not want to pass
"Some report.docx"
torm
, unless the file name contains the quotes. What you want is to passSome report.docx
unmolested torm
. KasiyA's answer (now) shows the general way to do that withfind
. [KasiyA: sorry for the wrong ping earlier.] -
Benny Abramovici over 9 years@Gilles Correct. In bash I generally quote the string to pass it unmolested. So by quoting what I meant was to send filename as a single argument to rm instead of being split up into
$0
and$1
etc. -
Rolf over 5 yearsOn OSX I do
xargs -0
instead ofxargs -r0
. -
Stéphane Chazelas about 3 yearsWith
xargs -I
, you'll still have problems with filenames that contain single quotes, double quotes, backslashes or newlines (leading blanks are also a problem, but with the output offind .
, that can only occur for filenames that contain<newline><blanks>
). -
Stéphane Chazelas about 3 yearsQuoting that second
{}
makes absolutely no difference here. That's just quoting for the shell, and that{}
doesn't need quoting in most shells. As far asxargs
is concerned, it receives an argument containing{}
(the two characters{
and}
) for both the{}
after-I
and"{}"
afterrm
. It is exactly the same asxargs -I {} rm {}
orxargs -I "{}" rm '{}'
-
Asim Jalis about 3 yearsStéphane: Good catch regarding the
-delete
and double quotes in file name. I have removed the-delete
. Regarding escaping quotes it needs a more robust sed expression. Do you have any suggestions on how to fix this? I’ll think about it. -
Stéphane Chazelas about 3 years