diff --git a/tests/ofproto-dpif.at b/tests/ofproto-dpif.at
index 121f84d..eb8647b 100644
--- a/tests/ofproto-dpif.at
+++ b/tests/ofproto-dpif.at
@@ -891,7 +891,7 @@ AT_SETUP([ofproto-dpif - Default Table Miss - OF1.0 (OFPTC_TABLE_MISS_CONTROLLER
 OVS_VSWITCHD_START([dnl
    add-port br0 p1 -- set Interface p1 type=dummy
 ])
-ON_EXIT([kill `cat ovs-ofctl.pid`])
+on_exit 'kill `cat ovs-ofctl.pid`'
 
 AT_CAPTURE_FILE([ofctl_monitor.log])
 
@@ -925,7 +925,7 @@ AT_SETUP([ofproto-dpif - Default Table Miss - OF1.3 (OFPTC_TABLE_MISS_DROP)])
 OVS_VSWITCHD_START([dnl
    add-port br0 p1 -- set Interface p1 type=dummy
 ])
-ON_EXIT([kill `cat ovs-ofctl.pid`])
+on_exit 'kill `cat ovs-ofctl.pid`'
 
 AT_CAPTURE_FILE([ofctl_monitor.log])
 AT_CHECK([ovs-ofctl del-flows br0])
@@ -953,7 +953,7 @@ AT_SETUP([ofproto-dpif - Table Miss - goto table and OFPTC_TABLE_MISS_CONTROLLER
 OVS_VSWITCHD_START([dnl
    add-port br0 p1 -- set Interface p1 type=dummy
 ])
-ON_EXIT([kill `cat ovs-ofctl.pid`])
+on_exit 'kill `cat ovs-ofctl.pid`'
 
 AT_CAPTURE_FILE([ofctl_monitor.log])
 AT_CHECK([ovs-ofctl -OOpenFlow12 add-flow br0 'table=0 actions=goto_table(1)'])
@@ -989,7 +989,7 @@ AT_SETUP([ofproto-dpif - Table Miss - resubmit and OFPTC_TABLE_MISS_CONTROLLER])
 OVS_VSWITCHD_START([dnl
    add-port br0 p1 -- set Interface p1 type=dummy
 ])
-ON_EXIT([kill `cat ovs-ofctl.pid`])
+on_exit 'kill `cat ovs-ofctl.pid`'
 
 AT_CAPTURE_FILE([ofctl_monitor.log])
 AT_CHECK([ovs-ofctl -OOpenFlow12 add-flow br0 'table=0 actions=resubmit(1,1)'])
@@ -1017,7 +1017,7 @@ AT_SETUP([ofproto-dpif - Table Miss - OFPTC_TABLE_MISS_CONTINUE])
 OVS_VSWITCHD_START([dnl
    add-port br0 p1 -- set Interface p1 type=dummy
 ])
-ON_EXIT([kill `cat ovs-ofctl.pid`])
+on_exit 'kill `cat ovs-ofctl.pid`'
 
 AT_CAPTURE_FILE([ofctl_monitor.log])
 AT_CHECK([ovs-ofctl add-flow br0 'table=1 dl_src=10:11:11:11:11:11 actions=controller'])
@@ -1076,7 +1076,7 @@ AT_SETUP([ofproto-dpif - Table Miss - goto table and OFPTC_TABLE_MISS_CONTINUE])
 OVS_VSWITCHD_START([dnl
    add-port br0 p1 -- set Interface p1 type=dummy
 ])
-ON_EXIT([kill `cat ovs-ofctl.pid`])
+on_exit 'kill `cat ovs-ofctl.pid`'
 
 AT_CAPTURE_FILE([ofctl_monitor.log])
 AT_DATA([flows.txt], [dnl
@@ -1140,7 +1140,7 @@ AT_SETUP([ofproto-dpif - Table Miss - resubmit and OFPTC_TABLE_MISS_CONTINUE])
 OVS_VSWITCHD_START([dnl
    add-port br0 p1 -- set Interface p1 type=dummy
 ])
-ON_EXIT([kill `cat ovs-ofctl.pid`])
+on_exit 'kill `cat ovs-ofctl.pid`'
 
 AT_CAPTURE_FILE([ofctl_monitor.log])
 AT_DATA([flows.txt], [dnl
@@ -1186,7 +1186,7 @@ AT_SETUP([ofproto-dpif - Table Miss - OFPTC_TABLE_MISS_DROP])
 OVS_VSWITCHD_START([dnl
    add-port br0 p1 -- set Interface p1 type=dummy
 ])
-ON_EXIT([kill `cat ovs-ofctl.pid`])
+on_exit 'kill `cat ovs-ofctl.pid`'
 
 AT_CAPTURE_FILE([ofctl_monitor.log])
 AT_CHECK([ovs-ofctl -OOpenFlow11 mod-table br0 all drop])
@@ -1214,7 +1214,7 @@ AT_SETUP([ofproto-dpif - Table Miss - goto table and OFPTC_TABLE_MISS_DROP])
 OVS_VSWITCHD_START([dnl
    add-port br0 p1 -- set Interface p1 type=dummy
 ])
-ON_EXIT([kill `cat ovs-ofctl.pid`])
+on_exit 'kill `cat ovs-ofctl.pid`'
 
 AT_CAPTURE_FILE([ofctl_monitor.log])
 AT_CHECK([ovs-ofctl del-flows br0])
@@ -1245,7 +1245,7 @@ AT_SETUP([ofproto-dpif - Table Miss - resubmit and OFPTC_TABLE_MISS_DROP])
 OVS_VSWITCHD_START([dnl
    add-port br0 p1 -- set Interface p1 type=dummy
 ])
-ON_EXIT([kill `cat ovs-ofctl.pid`])
+on_exit 'kill `cat ovs-ofctl.pid`'
 
 AT_CAPTURE_FILE([ofctl_monitor.log])
 AT_CHECK([ovs-ofctl del-flows br0])
@@ -1276,7 +1276,7 @@ AT_SETUP([ofproto-dpif - controller])
 OVS_VSWITCHD_START([dnl
    add-port br0 p1 -- set Interface p1 type=dummy
 ])
-ON_EXIT([kill `cat ovs-ofctl.pid`])
+on_exit 'kill `cat ovs-ofctl.pid`'
 
 AT_CAPTURE_FILE([ofctl_monitor.log])
 AT_DATA([flows.txt], [dnl
@@ -1546,7 +1546,7 @@ AT_SETUP([ofproto-dpif - MPLS handling])
 OVS_VSWITCHD_START([dnl
    add-port br0 p1 -- set Interface p1 type=dummy
 ])
-ON_EXIT([kill `cat ovs-ofctl.pid`])
+on_exit 'kill `cat ovs-ofctl.pid`'
 
 AT_CAPTURE_FILE([ofctl_monitor.log])
 AT_DATA([flows.txt], [dnl
@@ -2596,7 +2596,7 @@ AT_SETUP([ofproto-dpif - MPLS handling with goto_table])
 OVS_VSWITCHD_START([dnl
    add-port br0 p1 -- set Interface p1 type=dummy
 ])
-ON_EXIT([kill `cat ovs-ofctl.pid`])
+on_exit 'kill `cat ovs-ofctl.pid`'
 
 AT_CAPTURE_FILE([ofctl_monitor.log])
 AT_DATA([flows.txt], [dnl
@@ -2644,7 +2644,7 @@ AT_SETUP([ofproto-dpif - MPLS handling with write_actions])
 OVS_VSWITCHD_START([dnl
    add-port br0 p1 -- set Interface p1 type=dummy
 ])
-ON_EXIT([kill `cat ovs-ofctl.pid`])
+on_exit 'kill `cat ovs-ofctl.pid`'
 
 dnl N.B: The first (and only) action that accesses L3 data after the
 dnl pop_mpls action is present in write_actions. This exercises recirculation
@@ -2692,7 +2692,7 @@ AT_SETUP([ofproto-dpif - table-miss flow (OpenFlow 1.0)])
 OVS_VSWITCHD_START([dnl
    add-port br0 p1 -- set Interface p1 type=dummy
 ])
-ON_EXIT([kill `cat ovs-ofctl.pid`])
+on_exit 'kill `cat ovs-ofctl.pid`'
 
 AT_CAPTURE_FILE([ofctl_monitor.log])
 # A table-miss flow has priority 0 and no match
@@ -2732,7 +2732,7 @@ AT_SETUP([ofproto-dpif - table-miss flow (OpenFlow 1.3)])
 OVS_VSWITCHD_START([dnl
    add-port br0 p1 -- set Interface p1 type=dummy
 ])
-ON_EXIT([kill `cat ovs-ofctl.pid`])
+on_exit 'kill `cat ovs-ofctl.pid`'
 
 AT_CAPTURE_FILE([ofctl_monitor.log])
 # A table-miss flow has priority 0 and no match
@@ -2773,7 +2773,7 @@ AT_SETUP([ofproto-dpif - table-miss flow with async config (OpenFlow 1.3)])
 OVS_VSWITCHD_START([dnl
    add-port br0 p1 -- set Interface p1 type=dummy
 ])
-ON_EXIT([kill `cat ovs-ofctl.pid`])
+on_exit 'kill `cat ovs-ofctl.pid`'
 
 ovs-appctl time/stop
 
@@ -2841,7 +2841,7 @@ AT_SETUP([ofproto-dpif - table-miss flow (OpenFlow 1.4)])
 OVS_VSWITCHD_START([dnl
    add-port br0 p1 -- set Interface p1 type=dummy
 ])
-ON_EXIT([kill `cat ovs-ofctl.pid`])
+on_exit 'kill `cat ovs-ofctl.pid`'
 
 AT_CAPTURE_FILE([ofctl_monitor.log])
 # A table-miss flow has priority 0 and no match
@@ -2883,7 +2883,7 @@ AT_SETUP([ofproto-dpif - packet-in reasons (Openflow 1.3)])
 OVS_VSWITCHD_START([dnl
    add-port br0 p1 -- set Interface p1 type=dummy
 ])
-ON_EXIT([kill `cat ovs-ofctl.pid`])
+on_exit 'kill `cat ovs-ofctl.pid`'
 
 AT_CAPTURE_FILE([ofctl_monitor.log])
 AT_DATA([flows.txt], [dnl
@@ -2951,7 +2951,7 @@ AT_SETUP([ofproto-dpif - packet-in reasons (Openflow 1.4)])
 OVS_VSWITCHD_START([dnl
    add-port br0 p1 -- set Interface p1 type=dummy
 ])
-ON_EXIT([kill `cat ovs-ofctl.pid`])
+on_exit 'kill `cat ovs-ofctl.pid`'
 
 AT_CAPTURE_FILE([ofctl_monitor.log])
 AT_DATA([flows.txt], [dnl
@@ -3182,7 +3182,7 @@ AT_SETUP([ofproto-dpif - MPLS handling])
 OVS_VSWITCHD_START([dnl
    add-port br0 p1 -- set Interface p1 type=dummy
 ])
-ON_EXIT([kill `cat ovs-ofctl.pid`])
+on_exit 'kill `cat ovs-ofctl.pid`'
 
 AT_CAPTURE_FILE([ofctl_monitor.log])
 AT_DATA([flows.txt], [dnl
@@ -3299,7 +3299,7 @@ AT_SETUP([ofproto-dpif - VLAN+MPLS handling])
 OVS_VSWITCHD_START([dnl
    add-port br0 p1 -- set Interface p1 type=dummy
 ])
-ON_EXIT([kill `cat ovs-ofctl.pid`])
+on_exit 'kill `cat ovs-ofctl.pid`'
 
 AT_CAPTURE_FILE([ofctl_monitor.log])
 AT_DATA([flows.txt], [dnl
@@ -4733,7 +4733,7 @@ m4_define([CHECK_SFLOW_SAMPLING_PACKET],
   [AT_XFAIL_IF([test "$IS_WIN32" = "yes"])
   OVS_VSWITCHD_START([set Bridge br0 fail-mode=standalone])
 
-  ON_EXIT([kill `cat test-sflow.pid`])
+  on_exit 'kill `cat test-sflow.pid`'
   AT_CHECK([ovstest test-sflow --log-file --detach --no-chdir --pidfile 0:$1 > sflow.log], [0], [], [ignore])
   AT_CAPTURE_FILE([sflow.log])
   SFLOW_PORT=`parse_listening_port < test-sflow.log`
@@ -5076,7 +5076,7 @@ OVS_VSWITCHD_START([dnl
 		    other_config:lacp-port-priority=222			\
 		    other_config:lacp-aggregation-key=3333 ])
 
-ON_EXIT([kill `cat test-sflow.pid`])
+on_exit 'kill `cat test-sflow.pid`'
 AT_CHECK([ovstest test-sflow --log-file --detach --no-chdir --pidfile 0:127.0.0.1 > sflow.log], [0], [], [ignore])
 AT_CAPTURE_FILE([sflow.log])
 SFLOW_PORT=`parse_listening_port < test-sflow.log`
@@ -5121,7 +5121,6 @@ AT_XFAIL_IF([test "$IS_WIN32" = "yes"])
 OVS_VSWITCHD_START([set Bridge br0 fail-mode=standalone])
 
 dnl set up sFlow logging
-dnl ON_EXIT([kill `cat test-sflow.pid`])
 AT_CHECK([ovstest test-sflow --log-file --detach --no-chdir --pidfile 0:127.0.0.1 > sflow.log], [0], [], [ignore])
 AT_CAPTURE_FILE([sflow.log])
 SFLOW_PORT=`parse_listening_port < test-sflow.log`
@@ -5192,7 +5191,6 @@ AT_XFAIL_IF([test "$IS_WIN32" = "yes"])
 OVS_VSWITCHD_START([add-port br0 p0 -- set Interface p0 type=dummy ofport_request=1 options:ifindex=1010])
 
 dnl set up sFlow logging
-dnl ON_EXIT([kill `cat test-sflow.pid`])
 AT_CHECK([ovstest test-sflow --log-file --detach --no-chdir --pidfile 0:127.0.0.1 > sflow.log], [0], [], [ignore])
 AT_CAPTURE_FILE([sflow.log])
 SFLOW_PORT=`parse_listening_port < test-sflow.log`
@@ -5297,7 +5295,6 @@ table=0 dl_src=50:54:00:00:00:0b actions=pop_mpls:0x0800,2
 AT_CHECK([ovs-ofctl add-flows br0 flows.txt])
 
 dnl set up sFlow logging
-dnl ON_EXIT([kill `cat test-sflow.pid`])
 AT_CHECK([ovstest test-sflow --log-file --detach --no-chdir --pidfile 0:127.0.0.1 > sflow.log], [0], [], [ignore])
 AT_CAPTURE_FILE([sflow.log])
 SFLOW_PORT=`parse_listening_port < test-sflow.log`
@@ -5391,7 +5388,7 @@ m4_define([CHECK_NETFLOW_EXPIRATION],
   ADD_OF_PORTS([br0], 1, 2)
 
   ovs-appctl time/stop
-  ON_EXIT([kill `cat test-netflow.pid`])
+  on_exit 'kill `cat test-netflow.pid`'
   AT_CHECK([ovstest test-netflow --log-file --detach --no-chdir --pidfile 0:$1 > netflow.log], [0], [], [ignore])
   AT_CAPTURE_FILE([netflow.log])
   NETFLOW_PORT=`parse_listening_port < test-netflow.log`
@@ -5438,7 +5435,7 @@ m4_define([CHECK_NETFLOW_ACTIVE_EXPIRATION],
   [OVS_VSWITCHD_START([set Bridge br0 fail-mode=standalone])
   ADD_OF_PORTS([br0], 1, 2)
 
-  ON_EXIT([kill `cat test-netflow.pid`])
+  on_exit 'kill `cat test-netflow.pid`'
   AT_CHECK([ovstest test-netflow --log-file --detach --no-chdir --pidfile 0:$1 > netflow.log], [0], [], [ignore])
   AT_CAPTURE_FILE([netflow.log])
   NETFLOW_PORT=`parse_listening_port < test-netflow.log`
@@ -5770,7 +5767,7 @@ OVS_VSWITCHD_START([dnl
    add-port br0 p1 -- set Interface p1 type=dummy
 ])
 AT_CHECK([ovs-appctl vlog/set dpif:dbg dpif_netdev:dbg])
-ON_EXIT([kill `cat ovs-ofctl.pid`])
+on_exit 'kill `cat ovs-ofctl.pid`'
 
 AT_CAPTURE_FILE([ofctl_monitor.log])
 AT_DATA([flows.txt], [dnl
@@ -5806,7 +5803,7 @@ OVS_VSWITCHD_START([dnl
    add-port br0 p1 -- set Interface p1 type=dummy
 ])
 AT_CHECK([ovs-appctl vlog/set dpif:dbg dpif_netdev:dbg])
-ON_EXIT([kill `cat ovs-ofctl.pid`])
+on_exit 'kill `cat ovs-ofctl.pid`'
 
 AT_CAPTURE_FILE([ofctl_monitor.log])
 AT_DATA([flows.txt], [dnl
@@ -6116,7 +6113,7 @@ m4_define([CHECK_MEGAFLOW_NETFLOW],
   ADD_OF_PORTS([br0], [1], [2])
 
   dnl NetFlow configuration disables wildcarding relevant fields
-  ON_EXIT([kill `cat test-netflow.pid`])
+  on_exit 'kill `cat test-netflow.pid`'
   AT_CHECK([ovstest test-netflow --log-file --detach --no-chdir --pidfile 0:$1 > netflow.log], [0], [], [ignore])
   AT_CAPTURE_FILE([netflow.log])
   NETFLOW_PORT=`parse_listening_port < test-netflow.log`
diff --git a/tests/ofproto-macros.at b/tests/ofproto-macros.at
index a21887a..da9990c 100644
--- a/tests/ofproto-macros.at
+++ b/tests/ofproto-macros.at
@@ -67,7 +67,7 @@ m4_define([_OVS_VSWITCHD_START],
 
    dnl Start ovsdb-server.
    AT_CHECK([ovsdb-server --detach --no-chdir --pidfile --log-file --remote=punix:$OVS_RUNDIR/db.sock], [0], [], [stderr])
-    ON_EXIT_UNQUOTED([kill `cat ovsdb-server.pid`])
+   on_exit "kill `cat ovsdb-server.pid`"
    AT_CHECK([[sed < stderr '
 /vlog|INFO|opened log file/d
 /ovsdb_server|INFO|ovsdb-server (Open vSwitch)/d']])
@@ -79,7 +79,7 @@ m4_define([_OVS_VSWITCHD_START],
    dnl Start ovs-vswitchd.
    AT_CHECK([ovs-vswitchd $1 --detach --no-chdir --pidfile --log-file -vvconn -vofproto_dpif], [0], [], [stderr])
    AT_CAPTURE_FILE([ovs-vswitchd.log])
-   ON_EXIT_UNQUOTED([kill `cat ovs-vswitchd.pid`])
+   on_exit "kill `cat ovs-vswitchd.pid`"
    AT_CHECK([[sed < stderr '
 /ovs_numa|INFO|Discovered /d
 /vlog|INFO|opened log file/d
diff --git a/tests/ofproto.at b/tests/ofproto.at
index e3f08a8..507fe91 100644
--- a/tests/ofproto.at
+++ b/tests/ofproto.at
@@ -2774,7 +2774,7 @@ dnl This test checks that the role request/response messaging works
 dnl and that generation_id is handled properly.
 AT_SETUP([ofproto - controller role (OpenFlow 1.2)])
 OVS_VSWITCHD_START
-ON_EXIT([kill `cat c1.pid c2.pid`])
+on_exit 'kill `cat c1.pid c2.pid`'
 
 # Start two ovs-ofctl controller processes.
 AT_CAPTURE_FILE([monitor1.log])
@@ -2839,7 +2839,7 @@ dnl messages are sent when a controller's role gets changed from master
 dnl to slave.
 AT_SETUP([ofproto - controller role (OpenFlow 1.4)])
 OVS_VSWITCHD_START
-ON_EXIT([kill `cat c1.pid c2.pid`])
+on_exit 'kill `cat c1.pid c2.pid`'
 
 # Start two ovs-ofctl controller processes.
 AT_CAPTURE_FILE([monitor1.log])
@@ -3394,7 +3394,7 @@ echo n_msgs=$n_msgs
 OVS_VSWITCHD_START
 
 # Start a monitor watching the flow table, then make it block.
-ON_EXIT([kill `cat ovs-ofctl.pid`])
+on_exit 'kill `cat ovs-ofctl.pid`'
 ovs-ofctl monitor br0 watch: --detach --no-chdir --pidfile >monitor.log 2>&1
 AT_CAPTURE_FILE([monitor.log])
 ovs-appctl -t ovs-ofctl ofctl/block
diff --git a/tests/ovn-controller-vtep.at b/tests/ovn-controller-vtep.at
index 83badf9..5db9a35 100644
--- a/tests/ovn-controller-vtep.at
+++ b/tests/ovn-controller-vtep.at
@@ -24,7 +24,7 @@ m4_define([OVN_CONTROLLER_VTEP_START],
 
    dnl Start ovsdb-server.
    AT_CHECK([ovsdb-server --detach --no-chdir --pidfile --log-file --remote=punix:$OVS_RUNDIR/db.sock vswitchd.db vtep.db ovn-nb.db ovn-sb.db], [0], [], [stderr])
-    ON_EXIT_UNQUOTED([kill `cat ovsdb-server.pid`])
+   on_exit "kill `cat ovsdb-server.pid`"
    AT_CHECK([[sed < stderr '
 /vlog|INFO|opened log file/d
 /ovsdb_server|INFO|ovsdb-server (Open vSwitch)/d']])
@@ -33,7 +33,7 @@ m4_define([OVN_CONTROLLER_VTEP_START],
    dnl Start ovs-vswitchd.
    AT_CHECK([ovs-vswitchd --enable-dummy --disable-system --detach --no-chdir --pidfile --log-file -vvconn -vofproto_dpif], [0], [], [stderr])
    AT_CAPTURE_FILE([ovs-vswitchd.log])
-   ON_EXIT_UNQUOTED([kill `cat ovs-vswitchd.pid`])
+   on_exit "kill `cat ovs-vswitchd.pid`"
    AT_CHECK([[sed < stderr '
 /ovs_numa|INFO|Discovered /d
 /vlog|INFO|opened log file/d
@@ -49,7 +49,7 @@ m4_define([OVN_CONTROLLER_VTEP_START],
    dnl Start ovs-vtep.
    AT_CHECK([vtep-ctl add-ps br-vtep -- set Physical_Switch br-vtep tunnel_ips=1.2.3.4])
    AT_CHECK([ovs-vtep --log-file=ovs-vtep.log --pidfile=ovs-vtep.pid --detach br-vtep \], [0], [], [stderr])
-   ON_EXIT_UNQUOTED([kill `cat ovs-vtep.pid`])
+   on_exit "kill `cat ovs-vtep.pid`"
    AT_CHECK([[sed < stderr '
 /vlog|INFO|opened log file/d']])
    # waits until ovs-vtep starts up.
@@ -58,7 +58,7 @@ m4_define([OVN_CONTROLLER_VTEP_START],
    dnl Start ovn-northd.
    AT_CHECK([ovn-nbctl lswitch-add br-test])
    AT_CHECK([ovn-northd --detach --pidfile --log-file --ovnnb-db=unix:$OVS_RUNDIR/db.sock --ovnsb-db=unix:$OVS_RUNDIR/db.sock], [0], [], [stderr])
-   ON_EXIT_UNQUOTED([kill `cat ovn-northd.pid`])
+   on_exit "kill `cat ovn-northd.pid`"
    AT_CHECK([[sed < stderr '
 /vlog|INFO|opened log file/d']])
    AT_CAPTURE_FILE([ovn-northd.log])
@@ -66,7 +66,7 @@ m4_define([OVN_CONTROLLER_VTEP_START],
    dnl Start ovn-controllger-vtep.
    AT_CHECK([ovn-controller-vtep --detach --pidfile --log-file --vtep-db=unix:$OVS_RUNDIR/db.sock --ovnsb-db=unix:$OVS_RUNDIR/db.sock], [0], [], [stderr])
    AT_CAPTURE_FILE([ovn-controller-vtep.log])
-   ON_EXIT_UNQUOTED([kill `cat ovn-controller-vtep.pid`])
+   on_exit "kill `cat ovn-controller-vtep.pid`"
    AT_CHECK([[sed < stderr '
 /vlog|INFO|opened log file/d
 /reconnect|INFO|/d']])
diff --git a/tests/ovn-sbctl.at b/tests/ovn-sbctl.at
index 32e34bd..136885e 100644
--- a/tests/ovn-sbctl.at
+++ b/tests/ovn-sbctl.at
@@ -9,7 +9,7 @@ m4_define([OVN_SBCTL_TEST_START],
 
    dnl Start ovsdb-server.
    AT_CHECK([ovsdb-server --detach --no-chdir --pidfile --log-file --remote=punix:$OVS_RUNDIR/db.sock ovn-nb.db ovn-sb.db], [0], [], [stderr])
-    ON_EXIT_UNQUOTED([kill `cat ovsdb-server.pid`])
+   on_exit "kill `cat ovsdb-server.pid`"
    AT_CHECK([[sed < stderr '
 /vlog|INFO|opened log file/d
 /ovsdb_server|INFO|ovsdb-server (Open vSwitch)/d']])
@@ -17,7 +17,7 @@ m4_define([OVN_SBCTL_TEST_START],
 
    dnl Start ovn-northd.
    AT_CHECK([ovn-northd --detach --pidfile --log-file --ovnnb-db=unix:$OVS_RUNDIR/db.sock --ovnsb-db=unix:$OVS_RUNDIR/db.sock], [0], [], [stderr])
-   ON_EXIT_UNQUOTED([kill `cat ovn-northd.pid`])
+   on_exit "kill `cat ovn-northd.pid`"
    AT_CHECK([[sed < stderr '
 /vlog|INFO|opened log file/d']])
    AT_CAPTURE_FILE([ovn-northd.log])
diff --git a/tests/ovs-macros.at b/tests/ovs-macros.at
index c36ad06..058830b 100644
--- a/tests/ovs-macros.at
+++ b/tests/ovs-macros.at
@@ -17,6 +17,8 @@ m4_divert_push([PREPARE_TESTS])
 # directory.
 ovs_init() {
     ovs_base=`pwd`
+    trap '. "$ovs_base/cleanup"' 0
+    : > cleanup
     OVS_RUNDIR=$ovs_base; export OVS_RUNDIR
     OVS_LOGDIR=$ovs_base; export OVS_LOGDIR
     OVS_DBDIR=$ovs_base; export OVS_DBDIR
@@ -102,28 +104,18 @@ m4_define([OVS_APP_EXIT_AND_WAIT],
   [ovs-appctl -t $1 exit
    OVS_WAIT_WHILE([test -e $1.pid])])
 
-m4_define([ON_EXIT__], [trap '. ./cleanup' 0; cat - cleanup << $2 > __cleanup
-$1
-EOF
-mv __cleanup cleanup
-])
-
-dnl ON_EXIT([COMMANDS])
-dnl ON_EXIT_UNQUOTED([COMMANDS])
+dnl on_exit "COMMAND"
 dnl
-dnl Add the shell COMMANDS to a collection executed when the current test
+dnl Add the shell COMMAND to a collection executed when the current test
 dnl completes, as a cleanup action.  (The most common use is to kill a
 dnl daemon started by the test.  This is important to prevent tests that
 dnl start daemons from hanging at exit.)
 dnl
-dnl The only difference between ON_EXIT and ON_EXIT_UNQUOTED is that only the
-dnl latter performs shell variable (e.g. $var) substitution, command
-dnl substitution (e.g. `command`), and backslash escaping (e.g. \\ becomes \)
-dnl in COMMANDS at the time that ON_EXIT_UNQUOTED is encountered.  ON_EXIT,
-dnl in contrast, copies the literal COMMANDS and only executes shell expansion
-dnl at cleanup time.
-dnl
-dnl Cleanup commands are executed in the reverse order of execution of
-dnl these macros.
-m4_define([ON_EXIT], [ON_EXIT__([$1], ['EOF'])])
-m4_define([ON_EXIT_UNQUOTED], [ON_EXIT__([$1], [EOF])])
+dnl Cleanup commands are executed in the reverse order of calls to this
+dnl function.
+m4_divert_text([PREPARE_TESTS], [dnl
+on_exit () {
+    (echo "$1"; cat cleanup) > cleanup.tmp
+    mv cleanup.tmp cleanup
+}
+])
diff --git a/tests/ovs-monitor-ipsec.at b/tests/ovs-monitor-ipsec.at
index 16f11cf..7f13444 100644
--- a/tests/ovs-monitor-ipsec.at
+++ b/tests/ovs-monitor-ipsec.at
@@ -6,7 +6,7 @@ AT_SKIP_IF([$non_ascii_cwd])
 
 cp "$top_srcdir/vswitchd/vswitch.ovsschema" .
 
-ON_EXIT([kill `cat pid ovs-monitor-ipsec.pid`])
+on_exit 'kill `cat pid ovs-monitor-ipsec.pid`'
 
 mkdir etc etc/init.d etc/racoon etc/racoon/certs
 mkdir usr usr/sbin
diff --git a/tests/ovs-vsctl.at b/tests/ovs-vsctl.at
index d88ea27..f92544f 100644
--- a/tests/ovs-vsctl.at
+++ b/tests/ovs-vsctl.at
@@ -869,7 +869,7 @@ AT_CLEANUP
 
 AT_SETUP([database commands -- conditions])
 AT_KEYWORDS([ovs-vsctl])
-ON_EXIT([kill `cat pid`])
+on_exit 'kill `cat pid`'
 OVS_VSCTL_SETUP
 AT_CHECK(
   [RUN_OVS_VSCTL_TOGETHER(
@@ -1321,7 +1321,7 @@ dnl Create database.
 touch .conf.db.~lock~
 AT_CHECK([ovsdb-tool create conf.db $abs_top_srcdir/vswitchd/vswitch.ovsschema])
 AT_CHECK([ovsdb-server --detach --no-chdir --pidfile="`pwd`"/pid --private-key=$PKIDIR/ovsdbserver-privkey.pem --certificate=$PKIDIR/ovsdbserver-cert.pem --ca-cert=$PKIDIR/pki/switchca/cacert.pem --peer-ca-cert=$PKIDIR/ovsdbserver-cert.pem --remote=pssl:0:127.0.0.1 --unixctl="`pwd`"/unixctl --log-file="`pwd`"/ovsdb-server.log conf.db], [0], [ignore], [ignore])
-ON_EXIT_UNQUOTED([kill `cat pid`])
+on_exit "kill `cat pid`"
 SSL_PORT=`parse_listening_port < ovsdb-server.log`
 
 # During bootstrap, the connection gets torn down. So the o/p of ovs-vsctl is error.
diff --git a/tests/ovs-vswitchd.at b/tests/ovs-vswitchd.at
index 12a179a..8c2b2e0 100644
--- a/tests/ovs-vswitchd.at
+++ b/tests/ovs-vswitchd.at
@@ -5,7 +5,7 @@ dnl Open_vSwitch record) visible to ovs-vswitchd, but hand-rolled scripts
 dnl sometimes do.  At one point, "ovs-vswitchd --detach" would never detach
 dnl and use 100% CPU if this happened, so this test checks for regression.
 AT_SETUP([ovs-vswitchd detaches correctly with empty db])
-ON_EXIT([kill `cat ovsdb-server.pid ovs-vswitchd.pid`])
+on_exit 'kill `cat ovsdb-server.pid ovs-vswitchd.pid`'
 
 dnl Create database.
 touch .conf.db.~lock~
diff --git a/tests/ovs-xapi-sync.at b/tests/ovs-xapi-sync.at
index 08e32e2..69aae67 100644
--- a/tests/ovs-xapi-sync.at
+++ b/tests/ovs-xapi-sync.at
@@ -13,7 +13,7 @@ cp "$top_srcdir/vswitchd/vswitch.ovsschema" .
 cp "$top_srcdir/xenserver/usr_share_openvswitch_scripts_ovs-xapi-sync" \
    ovs-xapi-sync
 
-ON_EXIT([kill `cat pid ovs-xapi-sync.pid`])
+on_exit 'kill `cat pid ovs-xapi-sync.pid`'
 
 mkdir var var/run
 touch var/run/xapi_init_complete.cookie
diff --git a/tests/ovsdb-server.at b/tests/ovsdb-server.at
index a447e79..6bbaf92 100644
--- a/tests/ovsdb-server.at
+++ b/tests/ovsdb-server.at
@@ -165,7 +165,7 @@ AT_CLEANUP
 
 AT_SETUP([ovsdb-server/add-db and remove-db])
 AT_KEYWORDS([ovsdb server positive])
-ON_EXIT([kill `cat ovsdb-server.pid`])
+on_exit 'kill `cat ovsdb-server.pid`'
 ordinal_schema > schema1
 constraint_schema > schema2
 AT_CHECK([ovsdb-tool create db1 schema1], [0], [ignore], [ignore])
@@ -252,7 +252,7 @@ AT_SKIP_IF([test "$IS_WIN32" = "yes"])
 # Start ovsdb-server, initially with one db.
 ordinal_schema > schema
 AT_CHECK([ovsdb-tool create db1 schema], [0], [ignore], [ignore])
-ON_EXIT([kill `cat *.pid`])
+on_exit 'kill `cat *.pid`'
 AT_CHECK([ovsdb-server -v -vvlog:off --monitor --detach --no-chdir --pidfile --log-file db1])
 
 # Add the second database.
@@ -285,7 +285,7 @@ ordinal_schema > schema
 AT_CHECK([ovsdb-tool create db1 schema], [0], [ignore], [ignore])
 constraint_schema > schema2
 AT_CHECK([ovsdb-tool create db2 schema2], [0], [ignore], [ignore])
-ON_EXIT([kill `cat *.pid`])
+on_exit 'kill `cat *.pid`'
 AT_CHECK([ovsdb-server -v -vvlog:off --monitor --detach --no-chdir --pidfile --log-file db1 db2])
 
 # Remove the second database.
@@ -346,7 +346,7 @@ AT_CHECK(
         "table": "Manager",
         "uuid-name": "x",
         "row": {"target": "punix:socket2"}}]']], [0], [ignore], [ignore])
-ON_EXIT([kill `cat ovsdb-server.pid`])
+on_exit 'kill `cat ovsdb-server.pid`'
 AT_CHECK([ovsdb-server --detach --no-chdir --pidfile --remote=db:mydb,Root,managers --remote=db:mydb,Root,manager_options --log-file db], [0], [ignore], [ignore])
 ovs-appctl -t ovsdb-server time/warp 6000 1000
 AT_CHECK(
@@ -373,7 +373,7 @@ AT_SETUP([ovsdb-server/add-remote and remove-remote])
 AT_KEYWORDS([ovsdb server positive])
 ordinal_schema > schema
 AT_CHECK([ovsdb-tool create db schema], [0], [ignore], [ignore])
-ON_EXIT([kill `cat *.pid`])
+on_exit 'kill `cat *.pid`'
 AT_CHECK([ovsdb-server --detach --no-chdir --pidfile db])
 
 AT_CHECK([test ! -e socket1])
@@ -427,7 +427,7 @@ AT_SKIP_IF([test "$IS_WIN32" = "yes"])
 # Start ovsdb-server, initially with no remotes.
 ordinal_schema > schema
 AT_CHECK([ovsdb-tool create db schema], [0], [ignore], [ignore])
-ON_EXIT([kill `cat *.pid`])
+on_exit 'kill `cat *.pid`'
 AT_CHECK([ovsdb-server -v -vvlog:off --monitor --detach --no-chdir --pidfile --log-file db])
 
 # Add a remote.
@@ -456,7 +456,7 @@ AT_SKIP_IF([test "$IS_WIN32" = "yes"])
 # Start ovsdb-server, initially with no remotes.
 ordinal_schema > schema
 AT_CHECK([ovsdb-tool create db schema], [0], [ignore], [ignore])
-ON_EXIT([kill `cat *.pid`])
+on_exit 'kill `cat *.pid`'
 AT_CHECK([ovsdb-server -v -vvlog:off --monitor --detach --no-chdir --pidfile --log-file db])
 
 # Add a remote.
@@ -672,7 +672,7 @@ OVSDB_SERVER_SHUTDOWN
 AT_CLEANUP
 
 AT_SETUP([ovsdb-server combines updates on backlogged connections])
-ON_EXIT([kill `cat *.pid`])
+on_exit 'kill `cat *.pid`'
 
 # The maximum socket receive buffer size is important for this test, which
 # tests behavior when the receive buffer overflows.
diff --git a/tests/system-common-macros.at b/tests/system-common-macros.at
index 2761c08..c5691e7 100644
--- a/tests/system-common-macros.at
+++ b/tests/system-common-macros.at
@@ -16,7 +16,7 @@ m4_define([ADD_NAMESPACES],
    [m4_foreach([ns], [$@],
                [DEL_NAMESPACES(ns)
                 AT_CHECK([ip netns add ns])
-                ON_EXIT(DEL_NAMESPACES(ns))
+		on_exit 'DEL_NAMESPACES(ns)'
                ])
    ]
 )
@@ -60,7 +60,7 @@ m4_define([ADD_VETH],
       AT_CHECK([ovs-vsctl add-port $3 ovs-$1])
       NS_CHECK_EXEC([$2], [ip addr add $4 dev $1])
       NS_CHECK_EXEC([$2], [ip link set dev $1 up])
-      ON_EXIT([ip link del ovs-$1])
+      on_exit 'ip link del ovs-$1'
     ]
 )
 
@@ -89,7 +89,7 @@ m4_define([ADD_OVS_TUNNEL],
     AT_CHECK([ip addr add dev $2 $5])
     AT_CHECK([ip link set dev $2 up])
     AT_CHECK([ip link set dev $2 mtu 1450])
-    ON_EXIT([ip addr del dev $2 $5])
+    on_exit 'ip addr del dev $2 $5'
    ]
 )
 
diff --git a/tests/system-kmod-macros.at b/tests/system-kmod-macros.at
index 5fab7b7..1216db8 100644
--- a/tests/system-kmod-macros.at
+++ b/tests/system-kmod-macros.at
@@ -17,11 +17,11 @@ m4_define([_ADD_BR], [[add-br $1]])
 #
 m4_define([OVS_TRAFFIC_VSWITCHD_START],
   [AT_CHECK([modprobe openvswitch])
-   ON_EXIT([modprobe -r openvswitch])
+   on_exit 'modprobe -r openvswitch'
    m4_foreach([mod], [[vport_geneve], [vport_gre], [vport_lisp], [vport_stt], [vport_vxlan]],
               [modprobe -q mod || echo "Module mod not loaded."
-               ON_EXIT([modprobe -q -r mod])])
-   ON_EXIT([ovs-dpctl del-dp ovs-system])
+               on_exit 'modprobe -q -r mod'])
+   on_exit 'ovs-dpctl del-dp ovs-system'
    _OVS_VSWITCHD_START([])
    dnl Add bridges, ports, etc.
    AT_CHECK([ovs-vsctl -- _ADD_BR([br0]) -- set bridge br0 protocols=[[OpenFlow10,OpenFlow11,OpenFlow12,OpenFlow13,OpenFlow14,OpenFlow15]] fail-mode=secure -- $1 m4_if([$2], [], [], [| ${PERL} $srcdir/uuidfilt.pl])], [0], [$2])
diff --git a/tests/unixctl-py.at b/tests/unixctl-py.at
index cd0ac23..ec029fc 100644
--- a/tests/unixctl-py.at
+++ b/tests/unixctl-py.at
@@ -88,7 +88,7 @@ AT_CLEANUP
 
 AT_SETUP([unixctl server - Python])
 AT_SKIP_IF([test $HAVE_PYTHON = no])
-ON_EXIT([kill `cat test-unixctl.py.pid`])
+on_exit 'kill `cat test-unixctl.py.pid`'
 AT_CAPTURE_FILE([`pwd`/test-unixctl.py.log])
 AT_CHECK([$PYTHON $srcdir/test-unixctl.py --log-file --pidfile --detach])
 
diff --git a/tests/vlog.at b/tests/vlog.at
index 321ef2d..99565db 100644
--- a/tests/vlog.at
+++ b/tests/vlog.at
@@ -103,7 +103,7 @@ AT_CLEANUP
 
 AT_SETUP([vlog - vlog/reopen - Python])
 AT_SKIP_IF([test $HAVE_PYTHON = no])
-ON_EXIT([kill `cat test-unixctl.py.pid`])
+on_exit 'kill `cat test-unixctl.py.pid`'
 
 AT_CAPTURE_FILE([log])
 AT_CAPTURE_FILE([log.old])
@@ -128,7 +128,7 @@ AT_CLEANUP
 
 AT_SETUP([vlog - vlog/reopen without log file - Python])
 AT_SKIP_IF([test $HAVE_PYTHON = no])
-ON_EXIT([kill `cat test-unixctl.py.pid`])
+on_exit 'kill `cat test-unixctl.py.pid`'
 
 AT_CHECK([$PYTHON $srcdir/test-unixctl.py --pidfile --detach])
 
@@ -147,7 +147,7 @@ AT_SKIP_IF([test $HAVE_PYTHON = no])
 AT_SKIP_IF([test ! -c /dev/full])
 AT_SKIP_IF([echo > /dev/full])
 
-ON_EXIT([kill `cat test-unixctl.py.pid`])
+on_exit 'kill `cat test-unixctl.py.pid`'
 
 AT_CHECK([$PYTHON $srcdir/test-unixctl.py --log-file=`pwd`/log --pidfile --detach])
 AT_CHECK([APPCTL -t test-unixctl.py log message])
@@ -170,7 +170,7 @@ AT_CLEANUP
 
 AT_SETUP([vlog - vlog/set and vlog/list - Python])
 AT_SKIP_IF([test $HAVE_PYTHON = no])
-ON_EXIT([kill `cat test-unixctl.py.pid`])
+on_exit 'kill `cat test-unixctl.py.pid`'
 
 AT_CAPTURE_FILE([log])
 AT_CHECK([$PYTHON $srcdir/test-unixctl.py --log-file=`pwd`/log --pidfile --detach])
@@ -220,7 +220,7 @@ AT_CHECK([grep -q 'I<3OVS' log])
 AT_CLEANUP
 
 AT_SETUP([vlog - RFC5424 facility])
-ON_EXIT([kill `cat ovsdb-server.pid`])
+on_exit 'kill `cat ovsdb-server.pid`'
 
 dnl Create database.
 touch .conf.db.~lock~
@@ -258,7 +258,7 @@ AT_CLEANUP
 
 AT_SETUP([vlog - RFC5424 facility - Python])
 AT_SKIP_IF([test $HAVE_PYTHON = no])
-ON_EXIT([kill `cat test-unixctl.py.pid`])
+on_exit 'kill `cat test-unixctl.py.pid`'
 
 AT_CHECK([$PYTHON $srcdir/test-unixctl.py --log-file=`pwd`/log --pidfile \
 -vFACILITY:invalid --detach], [1], [], [test-unixctl.py: processing "FACILITY:invalid": Facility invalid is invalid
