diff --git a/bin/foamGetDict b/bin/foamGetDict
new file mode 100755
index 0000000000..35ded94201
--- /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 .
+#
+# 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<
+options:
+ -case Alternative case directory, default is the cwd
+ -ext File extension
+ -cfg Same as '-e cfg' for '.cfg' files
+ -no-ext Files without extension
+ -target 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=""
+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" = "" ]
+ 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" = "" ]
+ 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"
+
+
+#------------------------------------------------------------------------------