Take the 2-minute tour ×
Super User is a question and answer site for computer enthusiasts and power users. It's 100% free, no registration required.

I'm trying to delete a bunch of files in a certain directory (on Mac OS X using Terminal)

ls | grep \([1-9]\) | xargs rm

should do the trick, but it doesn't. I'm trying to delete any file with a single digit in parentheses in the filename (duplicates downloaded from the web), but it ends up doing something like this:

> rm: 520syllabus2010: No such file or
> directory rm: (3).pdf: No such file or
> directory

because it doesn't interpret the space correct. It should delete "520syllabus2010 (3).pdf"

What's the proper way of doing this?

Thanks, Jeff

share|improve this question
1  
Your example filename doesn't contain a literal #. –  Benjamin Bannier Jan 31 '11 at 20:45
1  
@honk: He's not looking for a literal #. –  Ignacio Vazquez-Abrams Jan 31 '11 at 20:47
1  
Due to expansion by the shell, this will not work as expected if the cwd has a file named e.g. (3). It's best to quote arguments so that the shell doesn't affect them. –  Ignacio Vazquez-Abrams Jan 31 '11 at 20:55
1  
You are being hit by The separator problem en.wikipedia.org/wiki/Xargs#The_separator_problem –  Ole Tange Feb 2 '11 at 0:22

1 Answer 1

up vote 15 down vote accepted

Short version:

rm *\([1-9]\)*

Do not pipe ls to xargs. Instead, pipe find ... -print0 to xargs -0, in order to avoid such problems.

find . -maxdepth 1 -name '*([1-9])*' -print0 | xargs -0 rm

...which can be written as:

find . -maxdepth 1 -name '*([1-9])*' -exec rm {} \;

and:

find . -maxdepth 1 -name '*([1-9])*' -delete

which can further be shortened to just rm with a wildcard.


Normally, ls and find separate file names with newlines, but xargs splits its input by newline or space, resulting in the behavior you see.

It's possible tell xargs to split only by newline, but files can have newlines in their names too. In fact, on Linux and BSD, the only disallowed character is the "null" or zero byte – so it's what you should use in such cases.

In example 2 above, -print0 tells find to separate filenames with a null byte; same for xargs -0. (A few other tools also have similar options, such as sort -z or grep -zZ.)

The "short version" uses a simple shell wildcard ("pattern" in bash manual – see section "Pathname Expansion").

share|improve this answer
1  
And just to be safe, it's better to use *" "\\([1-9]\\).* so that only files with a space before the paren'd number before the (a, to be fair) period are deleted. –  Ignacio Vazquez-Abrams Jan 31 '11 at 20:59
    
Not very familiar with this syntax, but based on the upvotes I gave it a try and what do you know... it worked! Thanks! –  Jeff Jan 31 '11 at 20:59
    
+1. -print0 is essential for correct piping to xargs. –  Chris W. Rea Jan 31 '11 at 21:10

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

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