0

I am using xargs and rm with find in order to remove files that follow a specific pattern defined by find as follows:

touch file
find . -name file | xargs rm

Everything works fine with the above code, but if I enter the -i option to rm, then executing:

touch file
find . -name file | xargs rm -i

prints:

rm: remove regular empty file ‘./file7’? user@host:$

without letting me enter y or n. Thus the file is not removed.

What's the problem here?

I am also aware of the xargs -p parameter which works but it is more general. That is, it prompts user to execute the specific command, which is not user-friendly.

EDIT: While using it in a shell script, I've found out that it executes the command I want but it also prints find's result, which is not preferable.

Also, when I pass the ls file2 command to cmd variable, it does not specifically print the file2's specs. Same thing happens when I type rm -i file2 . It prompts me to delete every single file in the directory.

This is my script:

#!/bin/bash
touch file{1..9}      # Create 9 files named file1,file2...file9
echo -n 'command: '  # Prompt user
read -e cmd             # read command
find . -exec ${cmd} '{}' +  

The only solution I can think of is to prompt the user separately for their preferred pattern. Then store that pattern to a variable and pass it as an argument to find command's -name option.

Something like this:

#!/bin/bash
touch file{1..9}     # Create 9 files named file1,file2...file9
echo -n 'command: '  # Prompt user for command
read -e cmd          # read command
echo -n 'pattern: '  # Prompt user for pattern
read -e pattern
find . -name "$pattern" -exec ${cmd} '{}' +  

But even with this solution, find's output is still printed and if the pattern field is left empty (i.e., the user just does not want to use a pattern) then problems occur.

Any ideas?

5 Answers 5

4

xargs reads data from stdin. When you use rm -i rm also tries to read the answer from stdin (try touch test && echo y | r -i test ; ls test) but stdin is closed by xargs (I assume) so rm reacts as if you had pressed ctrl-d at the prompt.

Another solution might be find's -exec option:

touch test
find . -name test -exec rm -i {} \;
2

You can use the POSIX -ok option for find to have it ask you whether or not to proceed with a command (other than the prompt it's just like -exec)

touch file
find . -name 'file' -ok rm -f {} \;

Output

< rm ... ./file > ? _
1

The problem here is that the stdin (the standard input) for the command ran from xargs (in this case rm) is redirected from /dev/null, and the stdin is the file descriptor used by rm to obtain the user's confirmation.

You could use the -a option so that rm obtain the list of files from an intermediate file previously generated by the find command (the -a option makes xargs to let the stdin untouched), in any case, I understand this may not be what you really want since it requires the intermediate file. A more straight approach similar to what you wanted can be obtained with the command below:

for i in $(find . -name file); do rm -i "$i"; done

0
     Just try that command

    find . -type f -iname filename -delete


  it is better to delete the need file.

   -type f ----> specific the file type ( file or directory or etc. )
   -iname  ----> ignore the case sensitive ( test or Test)
   -delete ----> its one of find command option, its delete files  
0

I had a similar problem, and was surprised when the command

find . -type f -name "*.txt" | xargs rm

unexpectedly deleted read-only files that matched the pattern.

Only afterward did I find the explanation in the rm man page:

if a file is unwritable, standard input is a terminal, and the -f or --force option is not given, or the -i or --interactive=always option is given, rm prompts the user for whether to remove the file.

One of the conditions to get the prompt is that standard input is a terminal, which is not true when you are piping output from another command to rm.

IMPORTANT LESSON: if stdin is not a terminal, rm will remove read-only files without any warning!!

In my case, the solution was to modify the find command to only return writable files:

find . -type f -writable -name "*.txt" | xargs rm

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .