3

ターミナルで使用できるのと同じ方法で、bash スクリプトで exec 3>myfifo を使用できないのはなぜですか?

名前付きパイプを使用して、awk フィルターを単純な「サーバー」に変えています。これは、クライアントからテキスト入力を受け取り、フィルター処理し、NUL でフラッシュできるはずです。

ターミナル 1 では、サーバーは次のように実行されています。

$ mkfifo to_server from_server;
$ 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; 
  echo "restarting..."; 
done

そして、NUL で終わる入力を入力パイプに入れ、出力パイプから読み取り、EOF をサーバーに送信せずに終了する単純なスクリプトを用意しました (サーバーは不要です)。再起動します):

#!/bin/bash
# According to http://mywiki.wooledge.org/BashFAQ/085 , using 
# `exec 3>mypipe; echo foo >&3;` instead of `echo foo >mypipe` 
# should ensure that the pipe does not get the EOF which closes it:
exec 3>to_server;
exec 4<from_server;

cat >&3;
echo -e '\0' >&3;
while read -rd '' <&4; do echo -n "$REPLY"; break; done;

ここで、ターミナル 2$ echo This is wrong | bash client.shで を実行すると元にThis is correct戻りますが、ターミナル 1 ではサーバーが再起動することが示されます。ただし、ターミナル 2 内から client.sh からコマンドを実行すると、再起動しません。

私もできるので、それはexecコマンドに関連しているようです

$ exec 3>to_server; exec 4<from_server;
$ echo "This is wrong" | sh client.sh

そして再起動しません。私なら

$ exec 3>&-; exec 4<&-

(もちろん、一度再起動します)そして

$ echo "This is wrong" | sh client.sh

毎回再起動します。そのため、スクリプト内の exec コマンドは効果がないようです。ただし、スクリプト内の exec コマンドの後に置くls /proc/$$/fd/と、実際には正しいパイプを指していることがわかります。

ここで何が欠けていますか?

4

2 に答える 2

3

私はそれを理解したと思います!

execコマンド 機能しますが、bash自体は、スクリプトを終了するときに開いているすべてのファイル記述子を閉じます。クライアントの最後にsleep5を追加すると、サーバーが最終的にシャットダウンするまでに5秒かかることがわかります。

したがって、解決策は、他のターミナルから名前付きパイプへのファイル記述子を開き、ターミナル3などで開いたままにすることです。

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

または、サーバーターミナル/スクリプト自体で:

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
于 2011-03-21T11:10:50.310 に答える
0

これは、(クライアント側の) 入力を 5 行のブロックで処理する、やや異なるバージョンです。

# 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
于 2011-04-01T19:32:36.187 に答える