How do I use exec 3>myfifo in a script, and not have echo foo>&3 close the pipe?

前端 未结 2 861
礼貌的吻别
礼貌的吻别 2020-12-19 21:50

Why can\'t I use exec 3>myfifo in the same manner in a bash script as I can in my terminal?

I\'m using named pipes to turn an awk filter into a simple \"se

相关标签:
2条回答
  • 2020-12-19 22:19

    Here's a somewhat different version that processes (client-side) input in five-line blocks.

    # using gawk for Mac OS X from: http://rudix.org/packages-ghi.html#gawk
    
    # server
    rm -v to_server from_server
    mkfifo to_server from_server
    (
    while true; do 
      (exec gawk '{sub("wrong", "correct");print;} /\0/ {fflush();}' <to_server >from_server) &
      bgpid=$!
      exec 3>to_server; exec 4<from_server
      wait "$bgpid"
      echo "restarting..." 
      done
    ) &
    
    
    # client.sh
    
    #!/bin/bash
    exec 3>to_server
    exec 4<from_server
    n=0
    
    clientserver() {
       n=0
       (
       while read -rd '' <&4; do echo -n "$REPLY"; break; done;
       IFS="" read -r -d $'\n' <&4 lines && printf 'found a trailing newline in from_server fifo \n' "$lines"
       ) &
       bgpid=$!
       printf '%s\n' "${lines[@]}" >&3
       printf '%b' '\000\n' >&3 
       wait $bgpid
       unset -v lines
       return 0
    }
    
    while IFS="" read -r -d $'\n' line; do
      n=$((n+=1))
      lines[$((n-1))]="$line"
      if [[ $n -eq 5 ]]; then
        clientserver
      fi
    done
    
    if [[ ${#lines[@]} -gt 0 ]]; then
      clientserver
    fi
    
    exit 0
    
    
    # test
    serverpid=$!
    echo This is wrong | bash client.sh
    printf '%s\n' {1..1007} | bash client.sh 
    kill -TERM $serverpid
    
    0 讨论(0)
  • 2020-12-19 22:31

    I think I figured it out!

    The exec commands do work, but bash itself closes all open file descriptors on exiting from the script. Adding sleep 5 to the end of the client shows that it takes 5 seconds for the server to finally shut down.

    So the solution is just to open some file descriptor to my named pipes from some other terminal, and just keep them open, e.g. in terminal 3:

    $ exec 3>to_server; exec 4<from_server
    $ # keep open for as long as server is open
    

    or, in the server terminal/script itself:

    while true; do 
      # Really, this awk script BEGIN's with reading in a huge file, 
      # thus the client-server model
      awk '{sub("wrong", "correct");print;} /\0/ {fflush();}' <to_server >from_server &
      AWKPID=$!
      exec 3>to_server; exec 4<from_server
      wait "$AWKPID"
      echo "restarting..."; 
    done
    
    0 讨论(0)
提交回复
热议问题