LLD: Design Unix “find” command for file search
Let's dissect it further
Unix file command searches for files. Now there can be different search criteria’s like search by file size, or search by extension or by a substring in file name. e.g. list all files which are less than 2 MB size or list all files whose extension is .pdf.
You can use strategy design pattern to implement the different search criteria’s.
A follow up is generally asked to combine queries like Boolean predicates AND, OR etc. e.g. list all files which are greater than 2MB in size AND their extension is “.jpg”.
You can use specification design pattern to combine result of search queries.
Design an in-memory file lookup tool similar to the Unix find command that:
Supports multiple search criteria:
File size
File extension
File name substring (easily extensible)
Supports Boolean composition of queries:
ANDORNOT
Below is a clean, Java design for:
✅ Basic
findusing Strategy Pattern (different search criteria)✅ Combining predicates using Specification Pattern (AND / OR / NOT)
This closely models how a real Unix find works under the hood.
Class Diagram
+---------------------+
| MyFile |
+---------------------+
| - name: String |
| - size: long |
| - extension: String |
+---------------------+
| + getName() |
| + getSize() |
| + getExtension() |
+---------------------+
▲
|
used by |
|
+--------------------------------+ +--------------------------------+
| SearchCriteria |<----------| FileSearcher |
+--------------------------------+ +--------------------------------+
| + matches(file: MyFile): bool | | + search(files, criteria):List |
+--------------------------------+ +--------------------------------+
▲ ▲ (uses SearchCriteria to filter files)
| |
| |
+----------------+ +---------------------+ +---------------------+
| SizeCriteria | | ExtensionCriteria | | NameContainsCriteria|
+----------------+ +---------------------+ +---------------------+
| - sizeLimit | | - extension: String | | - substring: String |
+----------------+ +---------------------+ +---------------------+
| + matches() | | + matches() | | + matches() |
+----------------+ +---------------------+ +---------------------+
+---------------------------+
| Specification |
+---------------------------+
| + isSatisfied(f: MyFile) |
| + and(spec): Specification|
| + or(spec): Specification |
| + not(): Specification |
+---------------------------+
▲
|
----------------------------------
| | |
+------------------+ +-----------------+ +---------------------+
| SizeSpec | | ExtensionSpec | | NameContainsSpec |
+------------------+ +-----------------+ +---------------------+
| - min/max size | | - extension | | - substring |
+------------------+ +-----------------+ +---------------------+
| + isSatisfied() | | + isSatisfied() | | + isSatisfied() |
+------------------+ +-----------------+ +---------------------+
+--------------------------------------+
| SpecificationFileSearcher |
+--------------------------------------+
| + search(files, spec): List<MyFile> |
+--------------------------------------+
(uses Specification instead of Strategy)
Explanation of the Design
1. MyFile
Represents a file with metadata such as:
name
extension
size
2. Strategy Pattern — SearchCriteria
Used for single-condition filters:
Size less than / greater than
Extension filter
Name contains filter
Each search rule becomes a separate class.
3. FileSearcher
Takes a list of files and a SearchCriteria object and returns matching files.
4. Specification Pattern — Specification
Supports combining multiple conditions using:
and()or()not()
Useful for:
size > 2MB AND extension == “.jpg”
5. SpecificationFileSearcher
Same as FileSearcher but uses Specification instead of SearchCriteria.
Core Model: MyFile
class MyFile {
private final String name;
private final long size; // in bytes
private final String extension;
public MyFile(String name, long size) {
this.name = name;
this.size = size;
this.extension = extractExtension(name);
}
private String extractExtension(String name) {
int idx = name.lastIndexOf(”.”);
return (idx == -1) ? “” : name.substring(idx);
}
public String getName() {
return name;
}
public long getSize() {
return size;
}
public String getExtension() {
return extension;
}
}
Strategy Pattern: SearchCriteria
interface SearchCriteria {
boolean matches(MyFile file);
}
Search by File Size
class SizeLessThanCriteria implements SearchCriteria {
private final long maxSize;
public SizeLessThanCriteria(long maxSize) {
this.maxSize = maxSize;
}
@Override
public boolean matches(MyFile file) {
return file.getSize() < maxSize;
}
}
class SizeGreaterThanCriteria implements SearchCriteria {
private final long minSize;
public SizeGreaterThanCriteria(long minSize) {
this.minSize = minSize;
}
@Override
public boolean matches(MyFile file) {
return file.getSize() > minSize;
}
}
Search by Extension
class ExtensionCriteria implements SearchCriteria {
private final String extension;
public ExtensionCriteria(String extension) {
this.extension = extension;
}
@Override
public boolean matches(MyFile file) {
return file.getExtension().equalsIgnoreCase(extension);
}
}
Search by Name Substring
class NameContainsCriteria implements SearchCriteria {
private final String substring;
public NameContainsCriteria(String substring) {
this.substring = substring;
}
@Override
public boolean matches(MyFile file) {
return file.getName().contains(substring);
}
}
File Search Engine
import java.util.*;
class FileSearcher {
public List<MyFile> search(List<MyFile> files, SearchCriteria criteria) {
List<MyFile> result = new ArrayList<>();
for (MyFile file : files) {
if (criteria.matches(file)) {
result.add(file);
}
}
return result;
}
}
Specification Pattern for AND / OR / NOT
interface Specification {
boolean isSatisfied(MyFile file);
default Specification and(Specification other) {
return file -> this.isSatisfied(file) && other.isSatisfied(file);
}
default Specification or(Specification other) {
return file -> this.isSatisfied(file) || other.isSatisfied(file);
}
default Specification not() {
return file -> !this.isSatisfied(file);
}
}
Wrapping Strategies as Specifications
class SizeGreaterThanSpec implements Specification {
private final long size;
public SizeGreaterThanSpec(long size) {
this.size = size;
}
@Override
public boolean isSatisfied(MyFile file) {
return file.getSize() > size;
}
}
class ExtensionSpec implements Specification {
private final String extension;
public ExtensionSpec(String extension) {
this.extension = extension;
}
@Override
public boolean isSatisfied(MyFile file) {
return file.getExtension().equalsIgnoreCase(extension);
}
}
class NameContainsSpec implements Specification {
private final String keyword;
public NameContainsSpec(String keyword) {
this.keyword = keyword;
}
@Override
public boolean isSatisfied(MyFile file) {
return file.getName().contains(keyword);
}
}
Search Using Combined Specifications
class SpecificationFileSearcher {
public List<MyFile> search(List<MyFile> files, Specification spec) {
List<MyFile> result = new ArrayList<>();
for (MyFile file : files) {
if (spec.isSatisfied(file)) {
result.add(file);
}
}
return result;
}
}
Driver Code (WITH AND / OR CONDITIONS)
import java.util.*;
public class UnixFindDemo {
public static void main(String[] args) {
List<MyFile> files = List.of(
new MyFile(”photo.jpg”, 5_000_000),
new MyFile(”resume.pdf”, 200_000),
new MyFile(”movie.mp4”, 900_000_000),
new MyFile(”pic.jpg”, 1_000_000),
new MyFile(”notes.txt”, 50_000)
);
// -------- Strategy Pattern Example ----------
FileSearcher searcher = new FileSearcher();
SearchCriteria smallFiles = new SizeLessThanCriteria(2_000_000); // < 2MB
List<MyFile> smallFileResults = searcher.search(files, smallFiles);
System.out.println(”Files < 2MB:”);
smallFileResults.forEach(f -> System.out.println(f.getName()));
// -------- Specification Pattern Example ----------
Specification sizeSpec = new SizeGreaterThanSpec(2_000_000); // > 2MB
Specification jpgSpec = new ExtensionSpec(”.jpg”);
// (size > 2MB) AND (extension == .jpg)
Specification combinedSpec = sizeSpec.and(jpgSpec);
SpecificationFileSearcher specSearcher = new SpecificationFileSearcher();
List<MyFile> result = specSearcher.search(files, combinedSpec);
System.out.println(”\nFiles > 2MB AND extension .jpg:”);
result.forEach(f -> System.out.println(f.getName()));
}
}

