认为
[root@iz2ze9wve43n2nyuvmsfx5z /]# find . -maxdepth 2 -type d | ls
bin dev home lib64 media opt root sbin sys usr
boot etc lib lost+found mnt proc run srv tmp var
ls 什么也没做,作为救援,我应该将它们重建为 ls 的列表
find . -type d | xargs ls
#millions of outputs
然而,grep 做得很好
[root@iz2ze9wve43n2nyuvmsfx5z /]# find . -maxdepth 2 -type d | grep home
./home
我怎样才能从底层理解中辨别出一个命令不是作为第二个发射器而诞生的,而不是尝试、错误测试和记住。
答案1
您要么学习并记住各种程序的功能,要么查看手册页。
的描述ls
是:
列出有关文件的信息(默认为当前目录)
其中 FILEs 指的是概要:
ls [选项]... [文件]...
要记住的重要部分ls
是,它将生成有关您提供的“文件”的信息 -在命令行上。该手册没有描述ls
读取任何输入(例如从管道)的任何方式。
ls
将手册页与以下内容进行对比,cat
例如手册页:
cat [选项]... [文件]...
将文件连接到标准输出。没有 FILE 或 FILE 为 - 时,读取标准输入。
有了cat
,你可以,cat /some/file
或者你可以echo hi | cat
。
因此,在你的第一个例子中,
find . -maxdepth 2 -type d | ls
find
做了一些工作,并在其标准输出上传递了一些(或没有)目录名称,这些目录名称变成了ls
的标准输入,它ls
立即被忽略。由于您ls
没有提供要列出的文件,因此它默认列出当前目录。
在你的第二个例子中,
find . -type d | xargs ls
find
去做(更多)工作,生成在标准输出上找到的每个目录,然后将其呈现为xargs
标准输入。手册页xargs
部分内容如下:
xargs 从标准输入读取项目...并执行命令一次或多次...
给定 stdin 上输入的行数,因此 thenls
会根据需要多次调用。
同样的想法也适用于您的第三个命令:
find . -maxdepth 2 -type d | grep home
find
将任何目录名称传递给grep
的 stdin; grep 的手册页再次部分说明:
grep 在指定的输入文件中搜索包含与给定模式匹配的行。如果未指定文件,或者给出了文件“-”,则 grep 搜索标准输入。
管道的想法很简单,但功能强大,您只需知道程序产生什么样的输出以及程序是否可以使用其标准输入上的输入。
grep
是在这些情况下最常用的工具之一。您可以将其用作主要命令:
grep some-text file1 file2 file3 ...
在这种情况下,grep
您知道文件的名称,或者您可以在其标准输入上发送输入:
cat file1 file2 file3 ... | grep some-text
...在这种情况下,grep 现在不再知道任何文件名(cat
知道它们,然后将其内容生成到标准输出),因此现在 grep 无法知道哪些文件包含文本 - 只能知道哪些行匹配。
将一堆命令链接在一起(通常被半开玩笑地称为“单行”,因为“单行”可以变得足够长,可以将终端窗口中的第二行包裹起来),这是很诱人的“管道”。同样,您必须确切地知道程序如何产生和消耗输入。
file1
给定名为、file2
和 的文件file3
,您能做类似的事情:
find . -name 'file*' | xargs cat
find
当生成三个文件名作为标准输出时,您不会感到惊讶-
file1
file2
file3
... xargs 编译一个列表并发送给cat
--
cat file1 file2 file3
...谁看到这三个文件名并尽职尽责地将其内容转储到您的屏幕上。
请注意名为“此处的文件名”的文件;上面的find
命令将输出:
file name here
file1
file2
file3
... xags 为其编译一个列表cat
--
cat file name here file1 file2 file3
...向其cat
抱怨(向stderr!):
cat:文件:没有这样的文件或目录
cat: name: 没有这样的文件或目录
cat: 这里: 没有这样的文件或目录
...后面是 file1、file2 和 file3 的内容。
您现在准备通过使用find ... -exec
或替代方案(例如find ... -print0 | xargs -0 ...
使用 NULL 作为文件名分隔符)来避免这种情况。