diff --git a/iocsh b/iocsh
index bde7ec7809031e41fcfd5abba27100e1d4d64792..3f9c3e5cbaa5158df40363d514cb1ecc55909a72 100755
--- a/iocsh
+++ b/iocsh
@@ -2,30 +2,29 @@
 
 help () {
     {
-    echo "usage: iocsh [options] [files]"
+    echo "usage: iocsh [options] [files] [macro=value] ..."
     echo "Start an EPICS iocsh and load files"
-    echo "Recognized filetypes: *.db *.dbt *.template *.subs *.subst *.dbd *.so"
     echo
     echo "Possible options:"
-    echo " -3.xx.yy: Set EPICS base version."
-    echo " -32: Force 32 bit version (on 64 bit systems)."
-    echo " -? or -h or --help: Show this page and exit."
-    echo " -v or --version: Show version and exit."
-    echo " -c: The next string is executed as a command by the EPICS shell."
-    echo " -s: The next string is a sequencer program (and arguments), run with 'seq'."
+    echo " -? or -h or --help: Show this page and exit"
+    echo " -v or --version: Show version and exit"
+    echo " -32: Force 32 bit host architecture (on 64 bit systems)"
+    echo " -x.z.y: (Up to 3 numbers) Use specific EPICS base version"
+    echo " -c: The next string is executed as a command by the EPICS shell"
+    echo " -s: The next string is a sequencer program (and arguments), run with 'seq'"
     echo "     This forces an 'iocInit' before running the program."
-    echo " -r: The next string is a module (and version), loaded via 'require'."
-    echo " -n: The next string is the IOC name (used for prompt)."
-    echo "     Default: dirname if parent dir is \"ioc\" otherwise hostname."
+    echo " -r: The next string is a module (and version), loaded via 'require'"
+    echo " -n: The next string is the IOC name (used for prompt)"
+    echo "     Default: dirname if parent dir is \"ioc\" otherwise hostname"
     echo
     echo "Supported filetypes:"
-    echo "*.db, *.dbt and *.template are loaded via 'dbLoadRecords'."
-    echo "  After the filename, you can specify substitutions like MACRO=value."
-    echo "*.subs and *.subst are loaded via 'dbLoadTemplate'."
-    echo "*.dbd is loaded via 'dbLoadDatabase'."
-    echo "*.so is loaded via 'ld' or 'dlload' (3.14.12 or higer)."
-    echo "If an argument is @file, more arguments are read from that file."
-    echo "All other files are executed as startup scripts by the EPICS shell."
+    echo "*.db, *.dbt and *.template are loaded via 'dbLoadRecords'"
+    echo "*.subs and *.subst are loaded via 'dbLoadTemplate'"
+    echo "*.dbd is loaded via 'dbLoadDatabase'"
+    echo "After the above files, you can specify macro substitutions like m1=v1 m2=v1"
+    echo "*.so is loaded via 'dlload' (or 'ld' before 3.14.12)"
+    echo "If an argument is @file, more arguments are read from that file"
+    echo "All other files are executed as startup scripts by the EPICS shell"
     } >&2
     exit
 }
@@ -37,20 +36,6 @@ version () {
     exit
 }
 
-case $1 in
-    ( -h | "-?" | -help | --help )
-        help
-        ;;
-    ( -v | -ver | --ver | -version | --version )
-        version
-        ;;
-    ( -3.* )
-        unset EPICS_BASE
-        BASE=${1#-}
-        shift
-    ;;
-esac
-
 # realpath and readlink are not available on all systems, let's try what works...
 rp() {
   ( realpath $1 || readlink -f $1 || readlink $1 || (cd -P $1 && echo $PWD) || (x=$(\ls -ld $1) && echo ${x##* }) || echo $1 ) 2>/dev/null
@@ -59,23 +44,31 @@ rp() {
 # if EPICS_HOST_ARCH is not set guess it
 if [ -z "$EPICS_HOST_ARCH" ]
 then
-    echo "EPICS_HOST_ARCH is not set"
     EPICS_HOST_ARCH=$(basename $(dirname $(rp $(which caRepeater))))
     if [ -n "$EPICS_HOST_ARCH" ]
     then
-        echo "Guessing EPICS_HOST_ARCH=$EPICS_HOST_ARCH"
+        echo "Guessing EPICS_HOST_ARCH=$EPICS_HOST_ARCH" >&2
     else
+        echo "EPICS_HOST_ARCH is not set" >&2
         exit 1
     fi
 fi
 
-# check if user requested 32 bit version on a 64 bit system
-case $1 in
-    ( -32 )
-        EPICS_HOST_ARCH=${EPICS_HOST_ARCH%_64}
-        shift
-    ;;
-esac
+while true
+do
+    case $1 in
+        ( -32 )
+            EPICS_HOST_ARCH=${EPICS_HOST_ARCH%_64}
+        ;;
+        ( -[1-9]* )
+            unset EPICS_BASE
+            BASE=${1#-}
+        ;;
+        ( * ) break
+        ;;
+    esac
+    shift
+done
 
 # Either EPICS or EPICS_BASE should be set to the install directory
 if [ -z "$EPICS_BASE" ]
@@ -87,25 +80,44 @@ then
         do
             if [ -d $EPICS ]
             then
-                break 2
+                break
             fi
-            echo "Cannot find any EPICS installation directory." >&2
-            echo "Try setting EPICS_BASE environment variable to full path" >&2
-            exit 1
         done
+        if [ ! -d "$EPICS" ]
+        then
+            EPICS=$(dirname $(dirname $(dirname $(dirname $(ldd $(which caRepeater) | awk '/libca/ {print $3}')))))
+            echo "Guessing EPICS=$EPICS"
+        fi
+        if [ ! -d "$EPICS" ]
+        then
+            echo "Cannot find EPICS installation directory." >&2
+            echo "Try setting EPICS environment variable." >&2
+            exit 1
+        fi
+    fi
+    if [ -z "$BASE" ]
+    then
+        EPICS_BASE=$(\ls -1vrd $EPICS/base/bin/{${EPICS_HOST_ARCH},${EPICS_HOST_ARCH%_64}} 2>/dev/null | head -n1)
+    else
+        # find highest (requested) EPICS version that supports our architecture (or its 32 bit version)
+        EPICS_BASE=$(\ls -1vrd $EPICS/base-$BASE*/bin/{${EPICS_HOST_ARCH},${EPICS_HOST_ARCH%_64}} 2>/dev/null | head -n1)
     fi
-    # find highest (requested) EPICS version that supports our architecture (or its 32 bit version)
-    EPICS_BASE=$(\ls -1vrd $EPICS/base*$BASE*/bin/{${EPICS_HOST_ARCH},${EPICS_HOST_ARCH%_64}} 2>/dev/null | head -n1)
     if [ -z $EPICS_BASE ]
     then
-        echo Cannot find any $BASE EPICS version for $EPICS_HOST_ARCH. >&2
+        if [ -z "$(\ls -1vrd $EPICS/base-$BASE*/ 2>/dev/null)" ]
+        then
+            echo "No EPICS $BASE installed." >&2
+            exit 1
+        fi
+        echo EPICS $BASE not available for EPICS_HOST_ARCH=$EPICS_HOST_ARCH. >&2
         exit 1
     fi
     # maybe we need to change from 64 bit to 32 bit
     if [ $EPICS_HOST_ARCH != ${EPICS_BASE#*/bin/} ]
     then
         EPICS_HOST_ARCH=${EPICS_BASE#*/bin/}
-        echo "No 64 bit version in ${EPICS_BASE%bin*}. Switch to 32 bit version $EPICS_HOST_ARCH"
+        echo "No 64 bit version in ${EPICS_BASE%bin*}." >&2
+        echo "Switching to 32 bit version $EPICS_HOST_ARCH." >&2
     fi
     EPICS_BASE=$(rp ${EPICS_BASE%bin*})
 fi
@@ -116,28 +128,13 @@ then
     exit 1
 fi
 
-# Check revision
-if [ -r $EPICS_BASE/configure/CONFIG_BASE_VERSION ]
-then
-BASE=$(awk -F '[ \t]*=[ \t]*' '
+# Get actual EPICS revision
+eval $(awk -F '[ \t]*=[ \t]*' '
     /^[ \t]*EPICS_VERSION[ \t]*=/ {v=$2}
     /^[ \t]*EPICS_REVISION[ \t]*=/ {r=$2}
-    /^[ \t]*EPICS_MODIFICATION[ \t]*=/ {m=$2}
-    END {print v"."r"."m}' < $EPICS_BASE/configure/CONFIG_BASE_VERSION)
-else
-BASE=$(basename $(rp $EPICS_BASE))
-BASE=${BASE#*base-}
-fi
-if [ "${BASE#3.}" = "$BASE" ]
-then
-    echo "Cannot find any EPICS base version" >&2
-    echo "Try setting EPICS_BASE environment variable to full path" >&2
-    exit 1
-fi
-export BASE
-BASEMINOR=${BASE#3.}
-BASEPATCH=${BASEMINOR#*.}
-BASEMINOR=${BASEMINOR%.*}
+    /^[ \t]*EPICS_MODIFICATION[ \t]*=/ {m=$2+0}
+    END {print "BASE="v"."r"."m";BASECODE="v*10000+r*100+m}
+' < $EPICS_BASE/configure/CONFIG_BASE_VERSION)
 
 # IOC name derives from hostname
 # (trailing possible '\r' under cygwin)
@@ -154,7 +151,7 @@ export IOC
 # Check for 64 bit versions, default to 32 bit
 if [ ! -d $EPICS_BASE/lib/${EPICS_HOST_ARCH} -a -d $EPICS_BASE/lib/${EPICS_HOST_ARCH%_64} ]
 then
-    echo "No 64 bit EPICS installation found. Defaulting to 32 bit"
+    echo "No 64 bit EPICS installation found. Defaulting to 32 bit" >&2
     EPICS_HOST_ARCH=${EPICS_HOST_ARCH%_64}
 fi
 export EPICS_HOST_ARCH
@@ -207,6 +204,14 @@ while [ "$#" -gt 0 ]
 do
   file=$1
   case $file in
+    ( -32 )
+        echo "-32 option must be set earlier" >&2
+        exit 1
+        ;;
+    ( -[1-9]* )
+        echo "EPICS version $file option must be set earlier" >&2
+        exit 1
+        ;;
     ( -h | "-?" | -help | --help )
         help
         ;;
@@ -216,7 +221,7 @@ do
     ( @* )              
         loadFiles $(cat ${file#@})
         ;;
-    ( *.db | *.template)
+    ( *.db | *.template | *.subs | *.subst | *.dbd )
         subst=""
         while [ "$#" -gt 1 ]
         do
@@ -229,17 +234,19 @@ do
                     ;;
             esac
         done
+        ;;&
+    ( *.db | *.template)
         echo "dbLoadRecords \"$file\",\"${subst#,}\""
         ;;
     ( *.subs | *.subst )
-        echo "dbLoadTemplate \"$file\""
+        echo "dbLoadTemplate \"$file\",\"${subst#,}\""
         ;;
     ( *.dbd )
         # some dbd files must be loaded before main to take effect
-        echo "dbLoadDatabase \"$file\",\"$DBD\""
+        echo "dbLoadDatabase \"$file\",\"$DBD\",\"${subst#,}\""
         ;;
     ( *.so )             
-        if [ $BASEMINOR -ge 15 -o $BASEPATCH -ge 12 ]
+        if [ $BASECODE -ge 31412 ]
         then
             echo "dlload \"$file\""
         else
@@ -279,19 +286,9 @@ do
         shift
         IOC="$1"
         ;;
-    ( -3.* )
-        echo "Version $file must be first argument" >&2
-        exit 1
-        ;;
-    ( -32 )
-        echo "-32 option must come before all others (except -3.xx.yy)" >&2
-        exit 1
-        ;;
     ( -* )
-        {
-        echo "unknown option $1"
-        echo "try: $(basename $0) --help"
-        } >&2
+        echo "Unknown option $1" >&2
+        echo "Try: $(basename $0) --help" >&2
         exit 1
        ;;
     ( * )                
@@ -311,7 +308,7 @@ trap "kill -s SIGTERM 0; stty sane; echo; rm -f $startup; " EXIT
 {
 echo "# date=\"$(date)\""
 echo "# user=\"${USER:-$(whoami)}\""
-for var in PWD BASE EPICS_HOST_ARCH SHELLBOX EPICS_CA_ADDR_LIST EPICS_DRIVER_PATH
+for var in IOC PWD BASE EPICS_HOST_ARCH SHELLBOX EPICS_CA_ADDR_LIST EPICS_DRIVER_PATH
 do
     echo "# $var=\"${!var}\""
 done
@@ -329,7 +326,7 @@ else # old driver pool model
     REQUIRE_DBD=$INSTBASE/iocBoot/R$BASE/dbd/$REQUIRE.dbd
 fi
 
-if [ $BASEMINOR -ge 15 -o $BASEPATCH -ge 12 ]
+if [ $BASECODE -ge 31412 ]
 then
     EXE=$EPICS_BASE/bin/$EPICS_HOST_ARCH/softIoc
     ARGS="-D $EPICS_BASE/dbd/softIoc.dbd"
@@ -346,6 +343,12 @@ else
     echo "${APP}_registerRecordDeviceDriver(pdbbase)"
 fi
 
+if [ ! -x $EXE ]
+then
+    echo "$EXE not found or not executable." >&2
+    exit 1
+fi
+
 if [ ! -f "$REQUIRE_LIB" ]
 then
     echo "Library $REQUIRE_LIB not found." >&2
@@ -388,5 +391,6 @@ then
 fi
 
 echo $EXE $ARGS $startup
+#enable core dumps
 ulimit -c unlimited
 eval "$LOADER $LOADERARGS $EXE" $ARGS "$startup" 2>&1