开发者

BASH: Best architecture for reading from two input streams

Simple script here:

a) constantly read from a socket and store values in an associative array

b) constantly read values from stdin and respond t/f if开发者_如何学C they already exist in the associative array

a & b are random events, not associated in any way.

The trick is accessing the array from both subprocesses (since putting a process in the background spawns it as a subprocess)

I'm thinking through the best strategy, and a few ideas occur, but I wonder if anyone has anything better in mind:

1) redirect the input from socket to stdin as a subprocess and handle both inputs in one while loop (data sizes are small, <30 characters, so I guess they will remain atomic?).

2) read the socket, then STDIN with small (0.1?) timeout values on read so as to mimic non-blocking I/O.

3) UPDATE: write the socket data to a file (actually have the other process write it directly to a file), then each time a request comes in to check if the value exists, process the entries in the file, adding them to the array (use file locking).


Bash is not the right tool for this. This problem is typically solved using the select(2) or poll(2) system calls, which allow you to wait on multiple file descriptors simultaneously without spinning. Bash does not have an interface to either of those.

I'd recommend using a scripting language such as Python or Perl (whatever you're comfortable with, really) that provides an interface with select or poll (e.g. Python's select module).


Don't know if this is fully practical and atomic enough in the described context, but using a client / server model and named pipes it's possible to create a while-loop that can distinguish between lines coming from a fifo or stdin.

The server constantly reads lines from a socket (/tmp/to) as well as lines from stdin (which is being redirected to the server via /tmp/to).

However, lines from stdin get marked by the del byte (\177) to be the first byte of the line.

Then the (backgrounded) client while-loop uses this first-byte-of-line to distinguish lines of different origin.

# terminal window 1

# server
(
rm -f /tmp/to /tmp/from
mkfifo /tmp/to /tmp/from
while true; do 
  while IFS="" read -r -d $'\n' line; do 
    printf '%s\n' "${line}"
  done </tmp/to >/tmp/from &
  bgpid=$!
  exec 3>/tmp/to
  exec 4</tmp/from
  trap "kill -TERM $bgpid; exit" 0 1 2 3 13 15
  wait "$bgpid"
  echo "restarting..."
done
) &
serverpid=$!

# client
(
exec 3>/tmp/to;
exec 4</tmp/from;
while IFS="" read -r -d $'\n' <&4 line; do
  if [[ "${line:0:1}" == $'\177' ]]; then 
    printf 'line from stdin: %s\n' "${line:1}"
  else       
    printf 'line from fifo: %s\n' "$line"
  fi
done &
trap "kill -TERM $"'!; exit' 1 2 3 13 15
while IFS="" read -r -d $'\n' line; do
  # can we make it atomic?
  # sleep 0.5
  # dd if=/tmp/to iflag=nonblock of=/dev/null  # flush fifo
  printf '\177%s\n' "${line}"
done >&3
) 
#kill -TERM $serverpid


# terminal window 2
echo hello > /tmp/to
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜