使用命名管道

有时你可能希望通过一个程序输出内容并将其输入另一个程序,但不能使用标准管道。

ls -l | grep ".log"

你可以简单地写一个临时文件:

touch tempFile.txt
ls -l > tempFile.txt
grep ".log" < tempFile.txt

这适用于大多数应用程序,但是,没有人会知道 tempFile 做了什么,如果它包含该目录中 ls -l 的输出,有人可能会删除它。这是命名管道发挥作用的地方:

mkfifo myPipe
ls -l > myPipe
grep ".log" < myPipe

myPipe 在技术上是一个文件(一切都在 Linux 中),所以让我们在我们刚刚创建管道的空目录中执行 ls -l

mkdir pipeFolder
cd pipeFolder
mkfifo myPipe
ls -l

输出是:

prw-r--r-- 1 root root 0 Jul 25 11:20 myPipe

注意权限中的第一个字符,它被列为管道而不是文件。

现在让我们做一些很酷的事情。

打开一个终端,记下目录(或创建一个目录,以便清理很容易),并制作一个管道。

mkfifo myPipe

现在让我们把东西放进烟斗里。

echo "Hello from the other side" > myPipe

你会注意到这个悬挂,管道的另一侧仍然关闭。让我们打开管道的另一边,然后让这些东西通过。

打开另一个终端并转到管道所在的目录(或者如果你知道它,则将其添加到管道中):

cat < myPipe

你会注意到,输出 hello from the other side 后,第一个终端中的程序结束,第二个终端中的程序也就完成了。

现在反向运行命令。从 cat < myPipe 开始,然后回复一些东西。它仍然有效,因为程序会等到一些东西放入管道才终止,因为它知道它必须得到一些东西。

命名管道可用于在终端之间或程序之间移动信息。

管道很小。一旦完整,写入器就会阻塞,直到某些读取器读取内容,因此你需要在不同的终端中运行读取器和写入器,或者在后台运行一个或另一个:

 ls -l /tmp > myPipe &
 cat < myPipe

使用命名管道的更多示例:

  • 示例 1 - 同一终端/同一 shell 上的所有命令

    $ { ls -l && cat file3; } >mypipe &
    $ cat <mypipe    
    # Output: Prints ls -l data and then prints file3 contents on screen
    
  • 示例 2 - 同一终端/同一 shell 上的所有命令

    $ ls -l >mypipe &
    $ cat file3 >mypipe &
    $ cat <mypipe
    #Output: This prints on screen the contents of mypipe. 
    

    注意显示 file3 的第一个内容然后显示 ls -l 数据(LIFO 配置)。

  • 示例 3 - 同一终端/同一 shell 上的所有命令

    $ { pipedata=$(<mypipe) && echo "$pipedata"; } &
    $ ls >mypipe 
    # Output: Prints the output of ls directly on screen 
    

    请注意,变量 $pipedata 不能在主终端/主 shell 中使用,因为使用 & 会调用子 shell,而 $pipedata 仅在此子 shell 中可用。

  • 示例 4 - 同一终端/同一 shell 上的所有命令

    $ export pipedata
    $ pipedata=$(<mypipe) &
    $ ls -l *.sh >mypipe
    $ echo "$pipedata"   
    #Output : Prints correctly the contents of mypipe
    

    由于变量的导出声明,这会在主 shell 中正确打印 $pipedata 变量的值。由于调用背景 shell(&),主终端/主 shell 没有挂起。