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.
This commit is contained in:
Tim Ledbetter 2023-09-18 17:13:12 +01:00 committed by Tim Flynn
parent 02d2d12592
commit c006ebe5a3
Notes: sideshowbarker 2024-07-16 22:11:09 +09:00
2 changed files with 38 additions and 5 deletions

View file

@ -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

View file

@ -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");