简体   繁体   English

Linux 为什么我不能将查找结果通过管道传送到 rm?

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

sorry if this is a noobie question but I can't find a good answer.抱歉,如果这是一个菜鸟问题,但我找不到好的答案。

To find then remove something I can use找到然后删除我可以使用的东西

find . -name ".txt" -exec rm "{}" \;

But why can't I just pipe the results to rm like但是为什么我不能像管道一样将结果传递给 rm

find . -name ".txt" | rm 

like I would pipe it to grep就像我会用管道将它传递给 grep

find . -name ".txt" | grep a

I've read from somewhere that rm doesn't take input from stdin and therefore I can't pipe it but what does that mean?我从某处读到 rm 不接受来自 stdin 的输入,因此我无法通过管道传输它,但这意味着什么? When I type in rm a.txt it reads from standard input just like I can grep right?当我输入 rm a.txt 时,它从标准输入中读取,就像我可以 grep 一样吗? Or is there a difference between stdin and command line.或者标准输入和命令行之间有区别。 Help!帮助!

To expand on @Alex Gitelman's answer: yes, there's a difference between "standard input" and the command line.扩展@Alex Gitelman 的回答:是的,“标准输入”和命令行之间存在差异。

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).当您键入rm a.txt b.txt c.txt ,您在rm之后列出的文件称为参数,并通过特殊变量(内部称为argv )提供给 rm。 The standard input, on the other hand, looks to a Unix program like a file named stdin .另一方面,标准输入看起来像一个名为stdin的文件的 Unix 程序。 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. rm与许多其他程序一样,从命令行获取参数但忽略标准输入。 You can pipe anything to it you like;你可以把任何你喜欢的东西用管道输送到它; it'll just throw that data away.它只会把这些数据扔掉。 That's where xargs comes in handy.这就是xargs派上用场的地方。 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.这将告诉find用空字符而不是换行符终止结果。 However, grep won't work as before then.但是, grep不会像以前那样工作。 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.这次tr用于将所有换行符转换为空字符。

"why can't I pipe find result to rm?" “为什么我不能通过管道找到结果到 rm?”

When you pipe something to a program, the pipe replaces the keyboard input.当您通过管道将某些内容传递给程序时,管道会替换键盘输入。 Keep this in mind and ask youself the next question: What would rm do with a keyboard?记住这一点并问自己下一个问题: rm会用键盘做什么? Delete your keystrokes ?删除您的按键? (a bit silly indeed) Accepting interactive control ? (确实有点傻)接受交互式控制? ( rm is not interactive except sometimes when it needs confirmation, which indeed can be given by a pipe.) rm不是交互式的,除非有时需要确认,这确实可以由管道给出。)

As a matter of fact, when rm is already running, you can't type commands to let it delete files....so you can't do that with a pipe either.事实上,当rm已经在运行时,你不能输入命令让它删除文件......所以你也不能用管道来做到这一点。

If you keep in mind that a pipe replaces the keyboard/screen combination, things will immediately appear more logical.如果您记住管道代替了键盘/屏幕组合,事情将立即显得更合乎逻辑。

Now the other way around.现在反过来。 You can pipe a datastream into grep .您可以将数据流通过管道传输到grep Does that mean that you can let grep read the keystrokes from your keyboard as input data instead ?这是否意味着您可以让 grep 将键盘上的击键读取为输入数据?

YES!是的! That is actually what it natively (without piping) does.这实际上是它本身(没有管道)所做的。

(btw note that you can not pipe nor type the search argument into grep ) (顺便说一句,您不能通过管道输入搜索参数,也不能将搜索参数输入grep

So now you know why you can't pipe to rm and expect it to work as a commandline argument.所以现在你知道为什么你不能通过管道连接到 rm期望它作为命令行参数工作。

tl;dr : tl;博士:

Anatomy of a program according to UNIX philosophy:根据 UNIX 哲学对程序进行剖析:
file in, file out, keyboard in, screen out.文件输入,文件输出,键盘输入,屏幕输出。 -> Pipe does only replace keyboard and screen. -> 管道只替换键盘和屏幕。

Pipe sends output of first command to the standard input of second.管道将第一个命令的输出发送到第二个的标准输入。 rm does not accept standard input so you can't pipe to it. rm不接受标准输入,因此您无法通过管道传输到它。 You could use xargs to achieve the same effect.您可以使用xargs来达到相同的效果。 You can find example for xargs specifically for your case in man page for xargs .您可以在xargs手册页中找到专门针对您的案例的xargs示例。

不使用管道的替代方法:

xargs rm -f <<< $(find . -name ".txt")

find .找到。 -name ".txt" | -name ".txt" | grep "foo" | grep "foo" | xargs -I{} rm {} xargs -I{} rm {}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM