diff --git a/src/Nitride.IO/IfFoundOutput.cs b/src/Nitride.IO/IfFoundOutput.cs
new file mode 100644
index 0000000..1a515ff
--- /dev/null
+++ b/src/Nitride.IO/IfFoundOutput.cs
@@ -0,0 +1,14 @@
+namespace Nitride.IO;
+
+public enum IfFoundOutput
+{
+ ///
+ /// If the entity is found, then remove it from output.
+ ///
+ RemoveFromOutput,
+
+ ///
+ /// If the entity is found, then keep it in the output sequence.
+ ///
+ ReturnInOutput,
+}
diff --git a/src/Nitride.IO/Nitride.IO.csproj b/src/Nitride.IO/Nitride.IO.csproj
index 219f01d..5c7e216 100644
--- a/src/Nitride.IO/Nitride.IO.csproj
+++ b/src/Nitride.IO/Nitride.IO.csproj
@@ -12,6 +12,7 @@
+
diff --git a/src/Nitride.IO/NitrideIOEnumerableEntityExtensions.cs b/src/Nitride.IO/NitrideIOEnumerableEntityExtensions.cs
new file mode 100644
index 0000000..de75785
--- /dev/null
+++ b/src/Nitride.IO/NitrideIOEnumerableEntityExtensions.cs
@@ -0,0 +1,90 @@
+using System.Collections.Generic;
+
+using Gallium;
+
+using MAB.DotIgnore;
+
+using Zio;
+
+namespace Nitride.IO;
+
+///
+/// Extension methods for working with paths.
+///
+public static class NitrideIOEnumerableEntityExtensions
+{
+ ///
+ /// Retrieves an entity from the sequence of entities.
+ ///
+ /// The sequence of iterations to parse.
+ /// The path to search for.
+ /// The entity pulled out, if found. Otherwise null.
+ /// If true, then remove the entity from the list.
+ /// The sequence of entities, optionally without one.
+ public static IEnumerable GetEntityByPath(
+ this IEnumerable input,
+ UPath path,
+ out Entity? foundEntity,
+ IfFoundOutput removeFromResults = IfFoundOutput.RemoveFromOutput)
+ {
+ List output = new();
+ foundEntity = null;
+
+ foreach (Entity entity in input)
+ {
+ // If we don't have a path, it isn't it.
+ if (!entity.TryGet(out UPath entityPath))
+ {
+ output.Add(entity);
+
+ continue;
+ }
+
+ // See if the path matches. If it doesn't, then return it.
+ if (entityPath != path)
+ {
+ output.Add(entity);
+
+ continue;
+ }
+
+ // We found the entity, so optionally return it.
+ foundEntity = entity;
+
+ if (removeFromResults == IfFoundOutput.ReturnInOutput)
+ {
+ output.Add(entity);
+ }
+ }
+
+ // Return the resulting output.
+ return output;
+ }
+
+ ///
+ /// Filters out entities that match a .gitignore style list and returns
+ /// the remaining entities.
+ ///
+ public static IEnumerable WhereNotIgnored(
+ this IEnumerable input,
+ IgnoreList ignoreList)
+ {
+ foreach (Entity entity in input)
+ {
+ // If we don't have a path, nothing to do.
+ if (!entity.TryGet(out UPath path))
+ {
+ yield return entity;
+ }
+
+ // See if the path matches. We use the "path is directory" set to false
+ // because Entity represents files, not directories.
+ string text = path.ToString();
+
+ if (!ignoreList.IsIgnored(text, false))
+ {
+ yield return entity;
+ }
+ }
+ }
+}
diff --git a/tests/Nitride.IO.Tests/Paths/GetEntityByPathTests.cs b/tests/Nitride.IO.Tests/Paths/GetEntityByPathTests.cs
new file mode 100644
index 0000000..46a82e4
--- /dev/null
+++ b/tests/Nitride.IO.Tests/Paths/GetEntityByPathTests.cs
@@ -0,0 +1,129 @@
+using System.Linq;
+
+using Gallium;
+
+using Nitride.IO.Contents;
+
+using Xunit;
+using Xunit.Abstractions;
+
+using Zio;
+
+namespace Nitride.IO.Tests;
+
+public class GetEntityByPathTests : NitrideIOTestBase
+{
+ public GetEntityByPathTests(ITestOutputHelper output)
+ : base(output)
+ {
+ }
+
+ [Fact]
+ public void FoundFile()
+ {
+ // Set up the test.
+ using NitrideIOTestContext context = this.CreateContext();
+
+ // Set up the file.
+ IFileSystem fileSystem = context.FileSystem;
+
+ fileSystem.CreateFile("/b1.txt");
+ fileSystem.CreateFile("/c1.md");
+
+ // Set up the operation.
+ ReadFiles readFiles = context.Resolve();
+
+ // Read and replace the paths.
+ IOrderedEnumerable output = readFiles.WithPattern("/**")
+ .Run()
+ .GetEntityByPath("/c1.md", out Entity? found)
+ .Select(
+ x => x.Get()
+ .ToString())
+ .OrderBy(x => x);
+
+ // Verify the results.
+ Assert.Equal(
+ new[]
+ {
+ "/b1.txt",
+ },
+ output);
+
+ Assert.NotNull(found);
+ Assert.Equal("/c1.md", found!.Get());
+ }
+
+ [Fact]
+ public void FoundFileAndKeep()
+ {
+ // Set up the test.
+ using NitrideIOTestContext context = this.CreateContext();
+
+ // Set up the file.
+ IFileSystem fileSystem = context.FileSystem;
+
+ fileSystem.CreateFile("/b1.txt");
+ fileSystem.CreateFile("/c1.md");
+
+ // Set up the operation.
+ ReadFiles readFiles = context.Resolve();
+
+ // Read and replace the paths.
+ IOrderedEnumerable output = readFiles.WithPattern("/**")
+ .Run()
+ .GetEntityByPath("/c1.md", out Entity? found, IfFoundOutput.ReturnInOutput)
+ .Select(
+ x => x.Get()
+ .ToString())
+ .OrderBy(x => x);
+
+ // Verify the results.
+ Assert.Equal(
+ new[]
+ {
+ "/b1.txt",
+ "/c1.md",
+ },
+ output);
+
+ Assert.NotNull(found);
+ Assert.Equal("/c1.md", found!.Get());
+ }
+
+ [Fact]
+ public void NotFoundFile()
+ {
+ // Set up the test.
+ using NitrideIOTestContext context = this.CreateContext();
+
+ // Set up the file.
+ IFileSystem fileSystem = context.FileSystem;
+
+ fileSystem.CreateFile("/b1.txt");
+ fileSystem.CreateFile("/c1.md");
+
+ // Set up the operation.
+ ReadFiles readFiles = context.Resolve();
+
+ // Read and replace the paths.
+ IOrderedEnumerable output = readFiles.WithPattern("/**")
+ .Run()
+ .GetEntityByPath("/not-found.md", out Entity? found)
+ .Select(
+ x => x.Get()
+ .ToString())
+ .OrderBy(x => x);
+
+ // Verify the results.
+ Assert.Equal(
+ new[]
+ {
+ "/b1.txt",
+ "/c1.md",
+ },
+ output);
+
+ Assert.Null(found);
+ }
+}
diff --git a/tests/Nitride.IO.Tests/Paths/WhereNotIgnoredTests.cs b/tests/Nitride.IO.Tests/Paths/WhereNotIgnoredTests.cs
new file mode 100644
index 0000000..c599d66
--- /dev/null
+++ b/tests/Nitride.IO.Tests/Paths/WhereNotIgnoredTests.cs
@@ -0,0 +1,58 @@
+using System.Linq;
+
+using MAB.DotIgnore;
+
+using Nitride.IO.Contents;
+
+using Xunit;
+using Xunit.Abstractions;
+
+using Zio;
+
+namespace Nitride.IO.Tests;
+
+public class WhereNotIgnoredTests : NitrideIOTestBase
+{
+ public WhereNotIgnoredTests(ITestOutputHelper output)
+ : base(output)
+ {
+ }
+
+ [Fact]
+ public void DoesIgnore()
+ {
+ // Set up the test.
+ using NitrideIOTestContext context = this.CreateContext();
+
+ // Set up the file.
+ IFileSystem fileSystem = context.FileSystem;
+
+ fileSystem.CreateFile("/b1.txt");
+ fileSystem.CreateFile("/c1.md");
+ fileSystem.CreateDirectory("/d");
+ fileSystem.CreateFile("/d/b2.txt");
+
+ // Set up the ignore file.
+ var ignore = new IgnoreList(new[] { "*.txt" });
+
+ // Set up the operation.
+ ReadFiles readFiles = context.Resolve();
+
+ // Read and replace the paths.
+ IOrderedEnumerable output = readFiles.WithPattern("/**")
+ .Run()
+ .WhereNotIgnored(ignore)
+ .Select(
+ x => x.Get()
+ .ToString())
+ .OrderBy(x => x);
+
+ // Verify the results.
+ Assert.Equal(
+ new[]
+ {
+ "/c1.md",
+ },
+ output);
+ }
+}