Linux Why Can't I Pipe Find Result to Rm

Linux why can't I pipe find result to rm?

To expand on @Alex Gitelman's answer: yes, there's a difference between "standard input" and the command line.

When you type rm a.txt b.txt c.txt, the files you list after rm are known as arguments and are made available to rm through a special variable (called argv internally). The standard input, on the other hand, looks to a Unix program like a file named stdin. A program can read data from this "file" just as it would if it opened a regular file on disk and read from that.

rm, like many other programs, takes its arguments from the command line but ignores standard input. You can pipe anything to it you like; it'll just throw that data away. That's where xargs comes in handy. It reads lines on standard input and turns them into command-line arguments, so you can effectively pipe data to the command line of another program. It's a neat trick.

For example:

find . -name ".txt" | xargs rm
find . -name ".txt" | grep "foo" | xargs rm

Note that this will work incorrectly if there are any filenames containing newlines or spaces.
To deal with filenames containing newlines or spaces you should use instead:

find . -name ".txt" -print0 | xargs -0 rm

This will tell find to terminate the results with a null character instead of a newline.
However, grep won't work as before then. Instead use this:

find . -name ".txt" | grep "foo" | tr "\n" "\0" | xargs -0 rm

This time tr is used to convert all newlines into null characters.

How to pipe the results of 'find' to mv in Linux

find ./ -name '*article*' -exec mv {}  ../backup  \;

OR

find ./ -name '*article*' | xargs -I '{}' mv {} ../backup

Why won't rm remove files passed in from find or sed?

The rm command doesn't take filenames from standard input. If you want to pipe from sed to rm, you can use xargs. For example:

find /home/mba/Desktop/ -type d -name "logs" | sed 's/$/\/\*/' | xargs rm -rf

Why doesn't rm -i work in a while read looping over the output of find?

Instead of looping over the content produced by the default -print action of find, use find's -exec action :

find . -name \*\.txt -exec rm -i -- {} +

In this command, {} represents the elements iterated over by find, and the + both delimits the command executed by find -exec and states that it should replace {} by as many elements it can at once (as an alternative you can use \; for the command to be executed once per element). -- after rm -i makes sure the file listed by find won't be interpreted as rm options if they start by a dash but correctly as filenames.

Not only is this more concise (although not more easily understandable) , but it also avoids problems related to special characters naïve solutions would have.

Why does a pipe to a command group only work for some commands?

The answer to your question is in comments of the linked answer.

Apparently ps -e is sending the header line first, then not sending anything, then buffering the rest of the output. head must think the stream is closed after the first line, so it exits, leaving grep to see the rest.

It only works by accident.

Is there any way to make it work universally?

Everything is possible, but, you may need to recode and recompile everything else. So... not possible, sorry.

How to remove all the results of a find command

find . -name '*.pyc' -exec rm -- '{}' +

From man find:

  • -exec utility [argument ...] ;
    True if the program named utility returns a zero value as its exit status. Optional arguments may be passed to the utility. The expression must be terminated by a semicolon (;). If you invoke
    find from a shell you may need to quote the semicolon if the shell would otherwise treat it as a control operator. If the string {} appears anywhere in the utility name or the arguments it is
    replaced by the pathname of the current file. Utility will be executed from the directory from which find was executed. Utility and arguments are not subject to the further expansion of shell patterns and constructs.

  • -exec utility [argument ...] {} +
    Same as -exec, except that {} is replaced with as many pathnames as
    possible for each invocation of utility. This behaviour is similar to that of > xargs(1).

{} doesn't need to be quoted in bash, but this helps compatibility with some other extended shells.

Receiving strange error when piping yes into rm -r command

Not really a Perl question.

The error comes from yes, so you would have to redirect the error stream of yes, too.

... ; yes 2>/dev/null | rm -r ...

But why don't you forget about yes and try rm -rf ... ?



Related Topics



Leave a reply



Submit