Simon 'corecode' Schubert corecode at
Fri Feb 15 03:30:22 PST 2008

Oliver Fromme wrote:
echo * | xargs rm

That's what I've been using in such cases for 15 years.
Works in every shell.  (Do not use it in world-writable
directories, though; it can be exploited.  But the same
is true for "rm *", too.)
I'll take the opportunity to educate the uneducated:

echo * | xargs rm, like find . -type f | xargs rm can be exploited, 
because xargs treats every whitespace as a separation character.

Now passing in (arbitrarily, due to public writable directory) white space 
separated strings can have bad side effects:

touch keep delete1 delete2
touch 'delete keep'	# evil communist spy
echo delete* | xargs rm
xargs will call rm with the parameters 'delete1', 'delete2', 'delete' and 
'keep'.  Voila, keep is gone.  rm will complain about delete not existing, 
but will happily remove keep anyways.

You can work around this by using find . -print0 | xargs -0, which is 
non-standard, IIRC.

Considering this, my rm() shell function was insecure as well :/

Now you also see why arguments and input from files (or pipes) is 
inherently different.  Arguments can contain arbitrary whitespace which 
won't get munged.  When reading from a fd, every program has to do the 
splitting itself, which is usually done on either a) any whitespace or b) 
newlines.  Now newline characters are valid in file names as well, so 
neither (a) nor (b) are a solution.

The only character not allowed in file names is ASCII NUL (binary 0).  But 
then, most tools work on newlines as separation characters and not on 
NULs.  Writing code which deals with NUL characters is even more 
complicated, as C strings are terminated by a NUL character, and you lose 
the ability to easily distinguish end-of-string and end-of-record.

As we can see, there *is* a problem, but not really in the argument space, 
but rather in the globbing / file name splitting/handling.  If somebody 
has a clever idea on how to approach this, please tell me.

rm * works, because the shell does the globbing and properly puts the file 
names into arguments, which then are not subject to white space splitting 

By the way, when dealing with file names in variables in shell, always quote:

for f in *; do
  mv "$f" "$f.2"
This is because shell does word splitting after variable expansion.  There 
is a special construct ("$@") for passing all parameters, without 
whitepsace splitting:

exec foo -b -a -r "$@"

Serve - BSD     +++  RENT this banner advert  +++    ASCII Ribbon   /"\
Work - Mac      +++  space for low €€€ NOW!1  +++      Campaign     \ /
Party Enjoy Relax   |      Against  HTML   \
Dude 2c 2 the max   !       Mail + News   / \

More information about the Kernel mailing list