如何将一个命名管道的输出反馈到另一个命名管道?

kip*_*oan 3 bash pipe sh named-pipes mkfifo

我正在为bash脚本添加一些自定义日志记录功能,并且无法弄清楚为什么它不会从一个命名管道获取输出并将其反馈回另一个命名管道.

这是脚本的基本版本(http://pastebin.com/RMt1FYPc):

#!/bin/bash

PROGNAME=$(basename $(readlink -f $0))
LOG="$PROGNAME.log"
PIPE_LOG="$PROGNAME-$$-log"
PIPE_ECHO="$PROGNAME-$$-echo"

# program output to log file and optionally echo to screen (if $1 is "-e")
log () {
  if [ "$1" = '-e' ]; then 
    shift
    $@ > $PIPE_ECHO 2>&1 
  else 
    $@ > $PIPE_LOG 2>&1 
  fi
}

# create named pipes if not exist
if [[ ! -p $PIPE_LOG ]]; then 
  mkfifo -m 600 $PIPE_LOG
fi
if [[ ! -p $PIPE_ECHO ]]; then 
  mkfifo -m 600 $PIPE_ECHO
fi

# cat pipe data to log file
while read data; do
  echo -e "$PROGNAME: $data" >> $LOG 
done < $PIPE_LOG &

# cat pipe data to log file & echo output to screen
while read data; do
  echo -e "$PROGNAME: $data"
  log echo $data   # this doesn't work
  echo -e $data > $PIPE_LOG 2>&1   # and neither does this
  echo -e "$PROGNAME: $data" >> $LOG   # so I have to do this
done < $PIPE_ECHO &

# clean up temp files & pipes
clean_up () {
  # remove named pipes
  rm -f $PIPE_LOG
  rm -f $PIPE_ECHO
}
#execute "clean_up" on exit
trap "clean_up" EXIT 

log echo "Log File Only"
log -e echo "Echo & Log File"
Run Code Online (Sandbox Code Playgroud)

我认为第34和35行的命令会从中$data取出$PIPE_ECHO并将其输出到$PIPE_LOG.但是,它不起作用.相反,我必须将该输出直接发送到日志文件,而不通过$PIPE_LOG.

为什么这不符合我的预期?

编辑:我把shebang改为"bash".但问题是一样的.

解决方案: AH的回答帮助我理解我没有正确使用命名管道.我已经解决了我的问题,甚至没有使用命名管道.解决方案在这里:http: //pastebin.com/VFLjZpC3

A.H*_*.H. 9

在我看来,你不明白命名管道到底是什么.命名管道不是普通管道的一个流.它是一系列普通管道,因为命名管道可以关闭,生产者端的关闭可能在消费者端显示为关闭.

可能的部分是:直到有没有更多的数据,消费者将读取的数据.没有更多数据意味着,在read调用时没有生产者打开命名管道.这意味着只有在没有至少一个生产者的时间点没有时间点的情况下,多个生产者才能喂养一个消费者.想一想自动关闭的门:如果有一个稳定的人流,通过将门把手递给下一个门或者同时挤压多个人来保持门始终打开,门就打开了.但是一旦门关闭,它就会保持关闭状态.

一点点演示应该让差异更加清晰:

打开三个炮弹.第一壳:

1> mkfifo xxx
1> cat xxx
Run Code Online (Sandbox Code Playgroud)

没有显示输出,因为cat已打开命名管道并正在等待数据.

第二壳:

2> cat > xxx 
Run Code Online (Sandbox Code Playgroud)

没有输出,因为这cat是一个生产者,它保持命名管道打开,直到我们告诉他明确地关闭它.

第三壳:

3> echo Hello > xxx
3>
Run Code Online (Sandbox Code Playgroud)

该生产者立即返回.

第一壳:

Hello
Run Code Online (Sandbox Code Playgroud)

消费者收到数据,写下来 - 由于还有一个消费者保持开门,继续等待.

第三壳

3> echo World > xxx
3> 
Run Code Online (Sandbox Code Playgroud)

第一壳:

World
Run Code Online (Sandbox Code Playgroud)

消费者收到数据,写下来 - 由于还有一个消费者保持开门,继续等待.

第二个Shell:写入cat > xxx窗口:

And good bye!
(control-d key)
2>
Run Code Online (Sandbox Code Playgroud)

第一个壳

And good bye!
1>
Run Code Online (Sandbox Code Playgroud)

^D关键的关闭最后生产的cat > xxx,因此消费者也退出.


在你的情况下,这意味着:

  • 您的log功能将尝试多次打开和关闭管道.不是个好主意.
  • 你的while循环都比你想象的更早退出.(检查一下(while ... done < $PIPE_X; echo FINISHED; ) &
  • 根据您的各种生产者和消费者的安排,门可能会被关闭,有时也不会关闭 - 您内置了竞争条件.(对于测试,您可以sleep 1log功能结束时添加一个.)
  • 你"testcases"只尝试一次尝试每种可能性 - 尝试多次使用它们(你会阻止,特别是使用sleeps),因为你的生产者可能找不到任何消费者.

所以我可以解释你的代码中的问题,但我不能告诉你一个解决方案,因为不清楚你的需求的边缘是什么.