I realized that awk is ideal for expect-like automation. The difficulty I faced was how can awk "control" another program's (in this case, an irc client) both stdin and stdout, i.e., awk would need to both read from the program's stdout and write to its stdin. I solved this program by creating a FIFO for taking inputs, and hook the program to it. Below is the detail:

First, let's set up our system:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
>>> mkfifo ups    # FIFO for taking inputs to IRC (upstream)

# Connect to IRC server. The <> style redirection ensures the
# EOF sent from other processes to the fifo doesn't cause this
# pipeline to terminate. It also ensures non-buffering mode
# so outputs are piped through without delay.
>>> nc chat.freenode.org 6667 <>ups | awk "$(cat <<'EOF'
{
print "[received] " $0
}

/kfkfkf/ {
print "+++++ I saw "kfkfkf! +++++"
print "hooohaaa" > "ups";
}
EOF
)"

Now this bot is up and running without human intervention. In case you want to interact with this IRC session, you could access the intput using cat:

1
2
3
4
5
6
7
8
9
>>> cat > ups

nick foobar
user foobar _ _ foobar

privmsg nickserv :identify <password>

privmsg <nick> :<msg>
privmsg <#channel> :<msg>

The system looks like this:

+---------------------------+
|                           |
|           cat             |
|                           |
+------------+--------------+
             |
             |
             v
          +--+--+
          | ups +<---------------+
          +--+--+                |
             |                   |
             |                   |
             v                   |
+------------+--------------+    |
|                           |    |
| nc chat.freenode.org 6667 |    |
|                           |    |
+------------+--------------+    |
             |                   |
             |                   |
             v                   |
+------------+--------------+    |
|                           |    |
|           awk             +----+
|                           |
+---------------------------+

One can connect to Freenode IRC using SSL instead, either one of below works:

openssl s_client -quiet -connect chat.freenode.org:6697
socat stdio openssl-connect:chat.freenode.org:6697

Taking it further

A pattern can be observed here - the main program is the IRC session, where its outputs are streaming through a pipeline unmodified. A set of bot programs takes IRC output as stdin, and their outputs are the bot command that should be sent back to the IRC. Then, we can use a utility tee program (proctee) to chain those bots together.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
mkfifo ups  # input to IRC
mkfifo display # "display" window

# read user and password
echo -n 'user: '; read user;
echo -n 'pass: '; stty -echo; read pass; stty echo

<>ups socat stdio openssl-connect:chat.freenode.org:6697 \
| { proctee -o display -- awk '{print}' ;: logging bot } \
| { proctee -o display -o ups -- bots/user.awk \
-v user="user" \
pass="pass" ;: user bot } \
| { proctee -o display -o ups -- bots/weather ;: weather bot } \
| { proctee -o display -o ups -- bots/time ;: time bot }