diff --git a/bin/foamGetDict b/bin/foamGetDict
new file mode 100755
index 0000000000000000000000000000000000000000..35ded94201d883fe0bc3dc0cffdb9ebc5d901126
--- /dev/null
+++ b/bin/foamGetDict
@@ -0,0 +1,354 @@
+#!/bin/bash
+#------------------------------------------------------------------------------
+# =========                 |
+# \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+#  \\    /   O peration     |
+#   \\  /    A nd           | Copyright (C) 2019 OpenCFD Ltd.
+#    \\/     M anipulation  |
+#------------------------------------------------------------------------------
+#                           | Copyright (C) 2018 OpenFOAM Foundation
+#------------------------------------------------------------------------------
+# License
+#     This file is part of OpenFOAM.
+#
+#     OpenFOAM is free software: you can redistribute it and/or modify it
+#     under the terms of the GNU General Public License as published by
+#     the Free Software Foundation, either version 3 of the License, or
+#     (at your option) any later version.
+#
+#     OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
+#     ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+#     FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+#     for more details.
+#
+#     You should have received a copy of the GNU General Public License
+#     along with OpenFOAM.  If not, see <http://www.gnu.org/licenses/>.
+#
+# Script
+#     foamGetDict
+#
+# Description
+#     Find an OpenFOAM dictionary file from OpenFOAM/etc/caseDicts/
+#     or {user,site} locations and copy it into the case directory.
+#
+# Environment
+#     FOAM_API
+#     WM_PROJECT_DIR
+#     WM_PROJECT_SITE
+#
+#------------------------------------------------------------------------------
+printHelp() {
+    cat<<USAGE
+
+Usage: ${0##*/} [OPTIONS] <file>
+options:
+  -case <dir>       Alternative case directory, default is the cwd
+  -ext  <ext>       File extension
+  -cfg              Same as '-e cfg' for '.cfg' files
+  -no-ext           Files without extension
+  -target <dir>     Target directory (default: system, or auto-detected)
+  -with-api=NUM     Alternative api value for searching
+  -help             Display short help and exit
+
+Find an OpenFOAM dictionary file from etc/caseDicts/ or {user,site} locations
+and copy it into the case directory. For example,
+
+    foamGetDict decomposeParDict
+    foamGetDict extrudeMeshDict
+    foamGetDict createPatchDict
+    foamGetDict surfaces
+
+USAGE
+    exit 0  # A clean exit
+}
+
+
+# Report error and exit
+die()
+{
+    exec 1>&2
+    echo
+    echo "Error encountered:"
+    while [ "$#" -ge 1 ]; do echo "    $1"; shift; done
+    echo
+    echo "See '${0##*/} -help' for usage"
+    echo
+    exit 1
+}
+
+
+#-------------------------------------------------------------------------------
+projectDir="$WM_PROJECT_DIR"                        # Project dir
+userDir="$HOME/.OpenFOAM"                           # As per foamVersion.H
+groupDir="${WM_PROJECT_SITE:-$projectDir/site}"     # As per foamVersion.H
+projectApi="$FOAM_API"
+
+#-------------------------------------------------------------------------------
+
+searchExt="<any>"
+unset targetDir
+
+while [ "$#" -gt 0 ]
+do
+    case "$1" in
+    -h | -help*)
+        printHelp
+        ;;
+    -case)
+        [ "$#" -ge 2 ] || die "'$1' option requires an argument"
+        cd "$2" 2>/dev/null || die "directory does not exist: '$2'"
+        shift
+        ;;
+    -with-api=*)
+        projectApi="${1#*=}"
+        ;;
+    -ext)
+        [ "$#" -ge 2 ] || die "'$1' option requires an argument"
+        searchExt="$2"
+        shift
+        ;;
+    -no-ext)
+        unset searchExt
+        ;;
+    -cfg)
+        searchExt="cfg"
+        ;;
+    -target)
+        [ "$#" -ge 2 ] || die "'$1' option requires an argument"
+        targetDir="$2"
+        shift
+        ;;
+    -target=*)
+        targetDir="${1#*=}"
+        ;;
+    --)
+        shift
+        break    # Stop here
+        ;;
+    -*)
+        die "invalid option '$1'"
+        ;;
+    *)
+        break
+        ;;
+    esac
+    shift
+done
+
+[ "$#" -eq 1 ] || die "Incorrect number of arguments"
+
+filePrefix="$1"
+
+# The target (time-dir) directory as one of (. | constant | system | 0)
+if [ -z "$targetDir" ]
+then
+    targetDir="system"
+
+    case "$filePrefix" in
+        All*)
+            targetDir="."
+            ;;
+        *Properties | *Cloud)
+            targetDir="constant"
+            ;;
+        s)
+           targetDir="0"
+           ;;
+    esac
+fi
+
+
+# No api specified -with-api= or from environment (FOAM_API)
+if [ -z "$projectApi" ]
+then
+    projectApi="$(foamEtcFile -show-api 2>/dev/null)"
+fi
+
+
+# Define the various places to be searched.
+# Similar to foamEtcFile, but with etc/caseDicts/ for the projectDir
+# Filter out nonexistent directories later
+
+searchDirs="${projectApi:+$userDir/$projectApi} $userDir \
+${projectApi:+$groupDir/$projectApi/etc} $groupDir/etc \
+$projectDir/etc/caseDicts";
+
+## echo "Using <$searchDirs>" 1>&2
+
+# ------------------------------------------------------------------------------
+
+# Search directories (searchDirs) for file
+# $1 = file-name
+#
+# Globals: searchDirs
+findFilesInDirs()
+{
+    local fileName="$1"
+    local dir
+
+    for dir in $searchDirs
+    do
+        if [ -d "$dir" ]
+        then
+            find "$dir" -name "$fileName" -type f | sort
+        fi
+    done
+}
+
+
+# Search directories (searchDirs) for file-prefix with extension (searchExt)
+#
+# $1 = file-prefix
+#
+# Globals: searchDirs, searchExt
+findFiles()
+{
+    local prefix="$1"
+
+    if [ -z "$searchExt" ]
+    then
+        # No extension
+        findFilesInDirs "$prefix"
+    elif [ "$searchExt" = "<any>" ]
+    then
+        # No extension or any extension
+        findFilesInDirs "$prefix"
+        findFilesInDirs "${prefix}.*"
+    else
+        # With specific extension
+        findFilesInDirs "${prefix}.$searchExt"
+    fi
+}
+
+
+# Slightly dressed up version of 'cp -v'
+copyFile()
+{
+    echo 1>&2
+    echo "Copying $1 to $2" 1>&2
+    \cp "$1" "$2"
+    echo 1>&2
+}
+
+
+# Priority locations for suggestion
+priorityLocations="\
+   caseDicts/postProcessing/ \
+   caseDicts/preProcessing/ \
+   caseDicts/general/ \
+   caseDicts/mesh/ \
+   caseDicts/surface/ \
+   caseDicts/solvers/"
+
+# Create an indexed list of suggestions
+listArgs()
+{
+    local arg loc n suggest
+    local i=0 pri=100
+
+    for arg in $1
+    do
+        i=$((i + 1))
+        echo "${i}) $arg" >&2
+
+        n=0
+        for loc in $priorityLocations
+        do
+            n=$((n + 1))
+            if [ "$n" -lt "$pri" ] && echo "$arg" | grep -q "$loc"
+            then
+                suggest="$i"
+                pri="$n"
+            fi
+        done
+    done
+
+    echo "$suggest"
+}
+
+
+# Select specified file by index from list
+selectFile()
+{
+    local files="$1"
+    local index="$2"
+    echo "$files" | tr -s '\n' ' ' | awk -v n="$index" '{print $n}'
+}
+
+
+# ------------------------------------------------------------------------------
+
+[ -s "system/controlDict" ] || \
+    echo "Warning: no OpenFOAM system/controlDict file" 1>&2
+
+[ -d "$targetDir" ] || \
+    die "target directory does not exist: '$targetDir'"
+
+# Begin search
+filesFound="$(findFiles "$filePrefix")"
+nFilesFound=0
+
+if [ -z "$filesFound" ]
+then
+    message="No file $filePrefix found"
+
+    if [ "$searchExt" = "<any>" ]
+    then
+        message="$message with/without file extensions"
+    elif [ -n "$searchExt" ]
+    then
+        message="$message with file extension '$searchExt'"
+    fi
+
+    die "$message"
+else
+    nFilesFound="$(echo "$filesFound" | xargs -n 1 | wc -l)"
+fi
+
+# Exactly one file found - we are done
+if [ "$nFilesFound" -eq 1 ]
+then
+    copyFile "$filesFound" "$targetDir"
+    exit 0
+fi
+
+# ------------------------------------------------------------------------------
+
+# Multiple files found - offer simple selection
+
+echo "Multiple files with \"$filePrefix\" prefix found:"
+echo
+
+suggest="$(listArgs "$filesFound")"
+
+if echo "$filesFound" | grep -q "annotated/"
+then
+    echo
+    echo "** Note: it may be easier not to use 'annotated/' files"
+fi
+
+echo
+echo "Choose file number [1-$nFilesFound]${suggest:+ (suggest $suggest)} :"
+read -r nFile
+
+# Nothing specified? Use default suggestion
+: "${nFile:=$suggest}"
+
+if [ -z "$nFile" ]
+then
+    echo "Nothing specify - re-run and enter a file number" 1>&2
+    exit 1
+elif [ "$nFile" -lt 1 ] || [ "$nFile" -gt "$nFilesFound" ]
+then
+    echo "\"$nFile\" is not a number between 1 and $nFilesFound" 1>&2
+    exit 1
+fi
+
+# Appears to have been successful. Select the file from the list
+
+file="$(selectFile "$filesFound" "$nFile")"
+
+copyFile "$file" "$targetDir"
+
+
+#------------------------------------------------------------------------------