launchd socket input I am trying to run a network server that is supposed to receive very short newline-terminated udp messages. The service plist looks like this

&lt;?xml version="1.0" encoding="UTF-8"?&gt;
&lt;!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"&gt;
&lt;plist version="1.0"&gt;
&lt;dict&gt;
        &lt;key&gt;Label&lt;/key&gt;
        &lt;string&gt;local.listener&lt;/string&gt;
        &lt;key&gt;Program&lt;/key&gt;
        &lt;string&gt;/bin/cat&lt;/string&gt;
        &lt;key&gt;Sockets&lt;/key&gt;
        &lt;dict&gt;
            &lt;key&gt;Listeners&lt;/key&gt;
            &lt;dict&gt;
                 &lt;key&gt;SockType&lt;/key&gt;
                 &lt;string&gt;dgram&lt;/string&gt;
                 &lt;key&gt;SockNodeName&lt;/key&gt;
                 &lt;string&gt;0.0.0.0&lt;/string&gt;
                 &lt;key&gt;SockServiceName&lt;/key&gt;
                 &lt;integer&gt;9999&lt;/integer&gt;
            &lt;/dict&gt;
        &lt;/dict&gt;
        &lt;key&gt;inetdCompatibility&lt;/key&gt;
        &lt;dict&gt;
            &lt;key&gt;Wait&lt;/key&gt;
            &lt;true/&gt;
        &lt;/dict&gt;
        &lt;key&gt;StandardOutPath&lt;/key&gt;
        &lt;string&gt;/tmp/test.stdout&lt;/string&gt;
&lt;/dict&gt;


and it loads and does what it is supposed to do (write message strings to /tmp/test.stdout).  However, I fail at replacing /bin/cat with a shell script
that reads the message into a variable and lets me do something with it.  I
thought that something like this should work:

#!/bin/sh
read MSG
echo $MSG


but this appears to block, and so does

#!/bin/sh
/bin/cat


while

#!/bin/sh
exec /bin/cat


still works. On the command line all three variants do about the same thing, e.g.,

$ echo 123 | ./mycat.sh
123


and nothing blocks.  Any insight into these subtle differences would be appreciated.
You're almost there. Wrap your first script in a while loop and you are set:

#!/bin/sh

while true; do
    read MSG
    echo $MSG
done


This is necessary to keep the process alive. Without the loop the script exits after the first line of input.

The exec approach works because you replace the current shell with /bin/cat. It is the same as calling /bin/cat directly.