Преглед на файлове

find: Add the `-path` and `-ipath` options

These options behave the same way as `-name` and `-iname` but match
the full file path instead of just the basename.
Tim Ledbetter преди 1 година
родител
ревизия
c006ebe5a3
променени са 2 файла, в които са добавени 38 реда и са изтрити 5 реда
  1. 13 0
      Base/usr/share/man/man1/find.md
  2. 25 5
      Userland/Utilities/find.cpp

+ 13 - 0
Base/usr/share/man/man1/find.md

@@ -54,6 +54,19 @@ specified commands, a `-print` command is implicitly appended.
   * `M`: mebibytes (1024 kibibytes)
   * `G`: gibibytes (1024 mebibytes)
 
+* `-path pattern`: Checks if the full file path matches the given global-style
+  pattern. This check matches against the full file name, starting from one of
+  the start points given on the command line. This means that using an absolute
+  path only makes sense in the case where the start point given on the command
+  line is an absolute path. For example, the following command will never match
+  anything:
+
+  `find bar -ipath '/foo/bar/test_file' -print`
+
+  The given path is compared against the current directory concatenated with the
+  basename of the current file. Because such a concatenation can never end in a
+  '/', specifying path argument that ends with a '/' will never match anything.
+* `-ipath pattern`: Functions identically to `-path` but is case-insensitive.
 * `-name pattern`: Checks if the file name matches the given global-style
   pattern (case sensitive).
 * `-empty`: File is either an empty regular file or a directory containing no

+ 25 - 5
Userland/Utilities/find.cpp

@@ -413,22 +413,34 @@ private:
     }
 };
 
-class NameCommand : public Command {
+class PathCommand : public Command {
 public:
-    NameCommand(char const* pattern, CaseSensitivity case_sensitivity)
+    enum class PathPart {
+        FullPath,
+        Basename
+    };
+
+    PathCommand(char const* pattern, CaseSensitivity case_sensitivity, PathPart path_part)
         : m_pattern(pattern, strlen(pattern))
         , m_case_sensitivity(case_sensitivity)
+        , m_path_part(path_part)
     {
+        if (path_part == PathPart::FullPath && m_pattern.ends_with('/'))
+            warnln("find: warning: path command will not match anything because it ends with '/'.");
     }
 
 private:
     virtual bool evaluate(FileData& file_data) const override
     {
-        return file_data.relative_path.basename().matches(m_pattern, m_case_sensitivity);
+        if (m_path_part == PathPart::Basename)
+            return file_data.relative_path.basename().matches(m_pattern, m_case_sensitivity);
+
+        return file_data.full_path().matches(m_pattern, m_case_sensitivity);
     }
 
     StringView m_pattern;
     CaseSensitivity m_case_sensitivity { CaseSensitivity::CaseSensitive };
+    PathPart m_path_part { PathPart::FullPath };
 };
 
 class RegexCommand : public Command {
@@ -766,14 +778,22 @@ static OwnPtr<Command> parse_simple_command(Vector<char*>& args)
         return make<SizeCommand>(args.take_first());
     } else if (arg == "-empty") {
         return make<EmptyCommand>();
+    } else if (arg == "-path") {
+        if (args.is_empty())
+            fatal_error("-path: requires additional arguments");
+        return make<PathCommand>(args.take_first(), CaseSensitivity::CaseSensitive, PathCommand::PathPart::FullPath);
+    } else if (arg == "-ipath") {
+        if (args.is_empty())
+            fatal_error("-ipath: requires additional arguments");
+        return make<PathCommand>(args.take_first(), CaseSensitivity::CaseInsensitive, PathCommand::PathPart::FullPath);
     } else if (arg == "-name") {
         if (args.is_empty())
             fatal_error("-name: requires additional arguments");
-        return make<NameCommand>(args.take_first(), CaseSensitivity::CaseSensitive);
+        return make<PathCommand>(args.take_first(), CaseSensitivity::CaseSensitive, PathCommand::PathPart::Basename);
     } else if (arg == "-iname") {
         if (args.is_empty())
             fatal_error("-iname: requires additional arguments");
-        return make<NameCommand>(args.take_first(), CaseSensitivity::CaseInsensitive);
+        return make<PathCommand>(args.take_first(), CaseSensitivity::CaseInsensitive, PathCommand::PathPart::Basename);
     } else if (arg == "-regex") {
         if (args.is_empty())
             fatal_error("-regex: requires additional arguments");