diff --git a/contrib/tree-1.6.0-matchdirs.patch b/contrib/tree-1.6.0-matchdirs.patch
new file mode 100644
index 0000000000000000000000000000000000000000..de2cfa2820868be25c1786f7b64ea7c3986bb831
--- /dev/null
+++ b/contrib/tree-1.6.0-matchdirs.patch
@@ -0,0 +1,162 @@
+From 57f931a7a8564379e7b2e5c31301dcd6c0e84b50 Mon Sep 17 00:00:00 2001
+From: "Jason A. Donenfeld" <Jason@zx2c4.com>
+Date: Thu, 4 Apr 2013 08:43:05 -0700
+Subject: [PATCH] Add --matchdirs to check patterns against directories
+
+This causes pattern matching to include the full contents of any
+directories that match the pattern, including sub-directories.
+---
+ doc/tree.1 | 10 +++++++++-
+ tree.c     | 46 ++++++++++++++++++++++++++++++++++++++++------
+ 2 files changed, 49 insertions(+), 7 deletions(-)
+
+diff --git a/doc/tree.1 b/doc/tree.1
+index 4b80852..7765f34 100644
+--- a/doc/tree.1
++++ b/doc/tree.1
+@@ -21,7 +21,7 @@
+ .SH NAME
+ tree \- list contents of directories in a tree-like format.
+ .SH SYNOPSIS
+-\fBtree\fP [\fB-acdfghilnpqrstuvxACDFQNSUX\fP] [\fB-L\fP \fIlevel\fP [\fB-R\fP]] [\fB-H\fP \fIbaseHREF\fP] [\fB-T\fP \fItitle\fP] [\fB-o\fP \fIfilename\fP] [\fB--nolinks\fP] [\fB-P\fP \fIpattern\fP] [\fB-I\fP \fIpattern\fP] [\fB--inodes\fP] [\fB--device\fP] [\fB--noreport\fP] [\fB--dirsfirst\fP] [\fB--version\fP] [\fB--help\fP] [\fB--filelimit\fP \fI#\fP] [\fB--si\fP] [\fB--prune\fP] [\fB--du\fP] [\fB--timefmt\fP \fIformat\fP] [\fIdirectory\fP ...]
++\fBtree\fP [\fB-acdfghilnpqrstuvxACDFQNSUX\fP] [\fB-L\fP \fIlevel\fP [\fB-R\fP]] [\fB-H\fP \fIbaseHREF\fP] [\fB-T\fP \fItitle\fP] [\fB-o\fP \fIfilename\fP] [\fB--nolinks\fP] [\fB-P\fP \fIpattern\fP] [\fB-I\fP \fIpattern\fP] [\fB--inodes\fP] [\fB--device\fP] [\fB--noreport\fP] [\fB--dirsfirst\fP] [\fB--version\fP] [\fB--help\fP] [\fB--filelimit\fP \fI#\fP] [\fB--si\fP] [\fB--prune\fP] [\fB--du\fP] [\fB--timefmt\fP \fIformat\fP] [\fB--matchdirs\fP] [\fIdirectory\fP ...]
+ .br
+ .SH DESCRIPTION
+ \fITree\fP is a recursive directory listing program that produces a depth
+@@ -123,6 +123,14 @@ Prints (implies -D) and formats the date according to the format string
+ which uses the \fBstrftime\fP(3) syntax.
+ .PP
+ .TP
++.B --matchdirs
++If a match pattern is specified by the -P option, this will cause the pattern
++to be applied to directory names (in addition to filenames).  In the event of a
++match on the directory name, matching is disabled for the directory's
++contents.If the --prune option is used, empty folders that match the pattern
++will not be pruned.
++.PP
++.TP
+ .B -o \fIfilename\fP
+ Send output to \fIfilename\fP.
+ .PP
+diff --git a/tree.c b/tree.c
+index 19cf368..187613d 100644
+--- a/tree.c
++++ b/tree.c
+@@ -28,7 +28,7 @@ static char *hversion="\t\t tree v1.6.0 %s 1996 - 2011 by Steve Baker and Thomas
+ bool dflag, lflag, pflag, sflag, Fflag, aflag, fflag, uflag, gflag;
+ bool qflag, Nflag, Qflag, Dflag, inodeflag, devflag, hflag, Rflag;
+ bool Hflag, siflag, cflag, Xflag, duflag, pruneflag;
+-bool noindent, force_color, nocolor, xdev, noreport, nolinks, flimit, dirsfirst, nosort;
++bool noindent, force_color, nocolor, xdev, noreport, nolinks, flimit, dirsfirst, nosort, matchdirs;
+ char *pattern = NULL, *ipattern = NULL, *host = NULL, *title = "Directory Tree", *sp = " ";
+ char *timefmt = NULL;
+ const char *charset = NULL;
+@@ -75,12 +75,13 @@ int main(int argc, char **argv)
+   char sizebuf[64];
+   off_t size = 0;
+   mode_t mt;
++  bool needfulltree;
+ 
+   q = p = dtotal = ftotal = 0;
+   aflag = dflag = fflag = lflag = pflag = sflag = Fflag = uflag = gflag = FALSE;
+   Dflag = qflag = Nflag = Qflag = Rflag = hflag = Hflag = siflag = cflag = FALSE;
+   noindent = force_color = nocolor = xdev = noreport = nolinks = FALSE;
+-  dirsfirst = nosort = inodeflag = devflag = Xflag = FALSE;
++  matchdirs = dirsfirst = nosort = inodeflag = devflag = Xflag = FALSE;
+   duflag = pruneflag = FALSE;
+   flimit = 0;
+   dirs = xmalloc(sizeof(int) * (maxdirs=4096));
+@@ -350,6 +351,11 @@ int main(int argc, char **argv)
+ 	      Dflag = TRUE;
+ 	      break;
+ 	    }
++	    if (!strncmp("--matchdirs",argv[i],11)) {
++	      j = strlen(argv[i])-1;
++	      matchdirs = TRUE;
++	      break;
++	    }
+ 	  }
+ 	default:
+ 	  fprintf(stderr,"tree: Invalid argument -`%c'.\n",argv[i][j]);
+@@ -387,16 +393,17 @@ int main(int argc, char **argv)
+   parse_dir_colors();
+   initlinedraw(0);
+ 
++  needfulltree = duflag || pruneflag || matchdirs;
+   /* Set our listdir function and sanity check options. */
+   if (Hflag) {
+-    listdir = (duflag || pruneflag)? html_rlistdir : html_listdir;
++    listdir = needfulltree ? html_rlistdir : html_listdir;
+     Xflag = FALSE;
+   } else if (Xflag) {
+-    listdir = (duflag || pruneflag)? xml_rlistdir : xml_listdir;
++    listdir = needfulltree ? xml_rlistdir : xml_listdir;
+     colorize = FALSE;
+     colored = FALSE; /* Do people want colored XML output? */
+   } else {
+-    listdir = (duflag || pruneflag)? unix_rlistdir : unix_listdir;
++    listdir = needfulltree ? unix_rlistdir : unix_listdir;
+   }
+   if (dflag) pruneflag = FALSE;	/* You'll just get nothing otherwise. */
+ 
+@@ -534,6 +541,7 @@ void usage(int n)
+ 	"  --charset X   Use charset X for terminal/HTML and indentation line output.\n"
+ 	"  --filelimit # Do not descend dirs with more than # files in them.\n"
+ 	"  --timefmt <f> Print and format time according to the format <f>.\n"
++	"  --matchdirs   Include directory names in -P pattern matching.\n"
+ 	"  -o filename   Output to file instead of stdout.\n"
+ 	"  -------- File options ---------\n"
+ 	"  -q            Print non-printable characters as '?'.\n"
+@@ -689,6 +697,8 @@ struct _info **getfulltree(char *d, u_long lev, dev_t dev, off_t *size, char **e
+   struct _info **dir, **sav, **p, *sp;
+   struct stat sb;
+   int n;
++  u_long lev_tmp;
++  char *tmp_pattern = NULL, *start_rel_path;
+   
+   *err = NULL;
+   if (Level >= 0 && lev > Level) return NULL;
+@@ -696,7 +706,29 @@ struct _info **getfulltree(char *d, u_long lev, dev_t dev, off_t *size, char **e
+     stat(d,&sb);
+     dev = sb.st_dev;
+   }
++
++  // if the directory name matches, turn off pattern matching for contents
++  if (matchdirs && pattern) {
++    lev_tmp = lev;
++    for (start_rel_path = d + strlen(d); start_rel_path != d; --start_rel_path) {
++      if (*start_rel_path == '/')
++        --lev_tmp;
++      if (lev_tmp <= 0) {
++        if (*start_rel_path)
++          ++start_rel_path;
++        break;
++      }
++    }
++    if (patmatch(start_rel_path,pattern) == 1) {
++      tmp_pattern = pattern;
++      pattern = NULL;
++    }
++  }
+   sav = dir = read_dir(d,&n);
++  if (tmp_pattern) {
++    pattern = tmp_pattern;
++    tmp_pattern = NULL;
++  }
+   if (dir == NULL) {
+     *err = scopy("error opening dir");
+     return NULL;
+@@ -745,7 +777,9 @@ struct _info **getfulltree(char *d, u_long lev, dev_t dev, off_t *size, char **e
+ 	saveino((*dir)->inode, (*dir)->dev);
+ 	(*dir)->child = getfulltree(path,lev+1,dev,&((*dir)->size),&((*dir)->err));
+       }
+-      if (pruneflag && (*dir)->child == NULL) {
++      // prune empty folders, unless they match the requested pattern
++      if (pruneflag && (*dir)->child == NULL &&
++	  !(matchdirs && pattern && patmatch((*dir)->name,pattern) == 1)) {
+ 	sp = *dir;
+ 	for(p=dir;*p;p++) *p = *(p+1);
+ 	n--;
+-- 
+1.9.2
+
diff --git a/man/pass.1 b/man/pass.1
index 668206d953e43a50f4157236c27efe570d218985..0035cdb8f61d74ef092448f74e83df7689eb9baf 100644
--- a/man/pass.1
+++ b/man/pass.1
@@ -72,6 +72,11 @@ by using the
 .BR tree (1)
 program. This command is alternatively named \fBlist\fP.
 .TP
+\fBfind\fP \fIpass-names\fP...
+List names of passwords inside the tree that match \fIpass-names\fP by using the
+.BR tree (1)
+program. This command is alternatively named \fBsearch\fP.
+.TP
 \fBshow\fP [ \fI--clip\fP, \fI-c\fP ] \fIpass-name\fP
 Decrypt and print a password named \fIpass-name\fP. If \fI--clip\fP or \fI-c\fP
 is specified, do not print the password but instead copy the first line to the
@@ -169,6 +174,25 @@ Password Store
 .br
 Alternatively, "\fBpass ls\fP".
 .TP
+Find existing passwords in store that match .com
+.B zx2c4@laptop ~ $ pass find .com
+.br
+Search Terms: .com
+.br
+\[u251C]\[u2500]\[u2500] Business 
+.br
+\[u2502]   \[u251C]\[u2500]\[u2500] some-silly-business-site.com 
+.br
+\[u2514]\[u2500]\[u2500] Email 
+.br
+    \[u251C]\[u2500]\[u2500] donenfeld.com 
+.br
+    \[u2514]\[u2500]\[u2500] zx2c4.com 
+.br
+
+.br
+Alternatively, "\fBpass search .com\fP".
+.TP
 Show existing password
 .B zx2c4@laptop ~ $ pass Email/zx2c4.com 
 .br
diff --git a/src/completion/pass.bash-completion b/src/completion/pass.bash-completion
index d80b18670afa5cec322f452f4b2acf1f8a5bd9e4..f7a51e94dec32e950fbd8431d115254b12867e7a 100644
--- a/src/completion/pass.bash-completion
+++ b/src/completion/pass.bash-completion
@@ -57,7 +57,7 @@ _pass()
 {
 	COMPREPLY=()
 	local cur="${COMP_WORDS[COMP_CWORD]}"
-	local commands="init ls show insert generate edit rm git help version"
+	local commands="init ls find show insert generate edit rm git help version"
 	if [[ $COMP_CWORD -gt 1 ]]; then
 		local lastarg="${COMP_WORDS[$COMP_CWORD-1]}"
 		case "${COMP_WORDS[1]}" in
diff --git a/src/completion/pass.fish-completion b/src/completion/pass.fish-completion
index 5c52eccac969eeb85243dc13dfb8f86e2fe80acf..d8f97e29467fd974687764ea4be8c7769ea7215e 100644
--- a/src/completion/pass.fish-completion
+++ b/src/completion/pass.fish-completion
@@ -106,3 +106,5 @@ complete -c $PROG -f -A -n '__fish_pass_uses_command git' -a 'commit' -d 'Commit
 complete -c $PROG -f -A -n '__fish_pass_uses_command git' -a 'push' -d 'Push changes to remote repo'
 complete -c $PROG -f -A -n '__fish_pass_uses_command git' -a 'pull' -d 'Pull changes from remote repo'
 complete -c $PROG -f -A -n '__fish_pass_uses_command git' -a 'log' -d 'View changelog'
+
+complete -c $PROG -f -A -n '__fish_pass_needs_command' -a find -d 'Command: find a password file or directory matching pattern'
diff --git a/src/completion/pass.zsh-completion b/src/completion/pass.zsh-completion
index 75903224686b0a48deb9c371bba4c2357c4d6270..ca983e2034d673b6bd3e54f7ef2be509e913977c 100644
--- a/src/completion/pass.zsh-completion
+++ b/src/completion/pass.zsh-completion
@@ -77,6 +77,7 @@ _pass () {
 		subcommands=(
 			"init:Initialize new password storage"
 			"ls:List passwords"
+			"find:Find password files or directories based on pattern"
 			"show:Decrypt and print a password"
 			"insert:Insert a new password"
 			"generate:Generate a new password using pwgen"
diff --git a/src/password-store.sh b/src/password-store.sh
index a7a5604be328e0fcd7d42009fc9b1b055d6148ef..706eada68430f305431dacc1f3e4bc225006bd2f 100755
--- a/src/password-store.sh
+++ b/src/password-store.sh
@@ -43,6 +43,8 @@ usage() {
 		Optionally reencrypt existing passwords using new gpg-id.
 	    $program [ls] [subfolder]
 		List passwords.
+	    $program find pass-names...
+	    	List passwords that match pass-names.
 	    $program [show] [--clip,-c] pass-name
 		Show existing password and optionally put it on the clipboard.
 		If put on the clipboard, it will be cleared in $CLIP_TIME seconds.
@@ -71,7 +73,7 @@ usage() {
 }
 is_command() {
 	case "$1" in
-		init|ls|list|show|insert|edit|generate|remove|rm|delete|git|help|--help|version|--version) return 0 ;;
+		init|ls|list|find|search|show|insert|edit|generate|remove|rm|delete|git|help|--help|version|--version) return 0 ;;
 		*) return 1 ;;
 	esac
 }
@@ -268,6 +270,25 @@ case "$command" in
 			exit 1
 		fi
 		;;
+	find|search)
+		if [[ -z "$@" ]]; then
+			echo "Usage: $program $command pass-names..."
+			exit 1
+		fi
+		if ! tree --help |& grep -q "^  --matchdirs"; then
+			echo "ERROR: $program: incompatible tree command"
+			echo
+			echo "Your version of the tree command is missing the relevent patch to add the"
+			echo "--matchdirs switch. Please ask your distribution to patch your version of"
+			echo "tree with:"
+			echo "   http://git.zx2c4.com/password-store/plain/contrib/tree-1.6.0-matchdirs.patch"
+			echo "Sorry for the inconvenience."
+			exit 1
+		fi
+		terms="$@"
+		echo "Search Terms: $terms"
+		tree -l --noreport -P "*${terms// /*|*}*" --prune --matchdirs "$PREFIX" | tail -n +2 | sed 's/\.gpg$//'
+		;;
 	insert)
 		multiline=0
 		noecho=1