Linux下的pipe, dev/null, vim -, 以及xargs

标准输入输出与pipe

标准输入(stdin, 编号0),标准输出(stdout,编号1),标准错误输出(stderr,编号2)是每个进程的io的一个抽象。标准输入默认是键盘输入,标准输出默认是显示屏。

Standard input is by default any text entered from the keyboard. It is the counterpart of standard output and standard error, which are by default the display monitor.

但默认值是可以改变的。<>,分别改变标准输入和标准输出。

node app.js > app.log这个命令里app的标准输出就被转到了app.log这个文件。

除了<>之外,pipe也是改变标准输入和输入的一种方式。pipe(符号|)能把一个程序的标准输出转成另一个程序的标准输入。这样一来可以玩的就多了。比较常见的是把一个程序的输出pipe给grep,比方说搜索一个与nodejs有关的进程,

ps aux | grep node

当看到一些pipe应用的例子之后,你肯定会像我当年一样被这么赞的东西感动到落泪。。。好赞的Unix philosophy。。。只做一件事,做好这件事。。。潸然泪下。。。

可是,当你敲这个命令时

echo abcd | vim

vim会给你一个比较奇怪的信息

Vim: Warning: Input is not from a terminal

原因是vim需要标准输入来自terminal而不是另一个程序的输出。当然还是可以pipe输出给vim的,用

echo abcd | vim -就行。详情可参见man vim

很多接受参数linux命令特殊对待-,遇到它就接受标准输入为输入。比较常见的是和tar一起用。

所以,Unix philosophy只是一个guideline而已,到底遵不遵循还是看写命令的人。

/dev/null

将一个程序的输出转存到一个文件是很简单的

node server.js > server.log

但如果不关心这个程序的输出是什么可以这么做,

node server.js > /dev/null 2>&1 &。这样标准输出和错误输出都导向了/dev/null。。。而/dev/null是一个黑洞。。。这么做就是说,我不在乎这个程序的输出是什么,让它闭嘴就是了。最后的&让它在背景运行。

xargs

貌似能否正确使用这个命令似乎是区分命令行小弟和命令行小哥的标志之一。跟xargs混的很面熟,但不太了解也没在意,终于内心惭愧用man翻了一下它的简介。

第一句话是怎么说的,(这个输出来自我的Mac,和Ubuntu的还不一样。BSD vs GUN 😅)

xargs – construct argument list(s) and execute utility

在Ubuntu,是这么说的,

xargs – build and execute command lines from standard input

大同小异。不过觉得BSD的这句描述更清楚,因为提到了参数argument这个关键词。

要理解xargs,我们可以考虑这么一个问题:如何在vue的源码repo里面搜索所有包含有vue这个词的文件?

find . -name '*.js' | grep vue

可惜的是,这个命令只列出名字里包含vue这个字符串的文件,而不是搜索这些文件里包含这个字符串的行。我们想把find命令得到的结果作为参数传给grepxargs就是专门做这个的,它把find输出的字符串作为参数传给grepxargs用space, tab, newline and end-of-file来分割字符串。在处理名字里可能有空格的文件时,find可以加上-print0配合xargs-0使用。即,

find . -name *.js -print0 | xargs -0 grep vue