find: Add the -maxdepth
and -mindepth
options
The `-maxdepth` option limits the number of levels `find` will descend into the file system for each given starting point. The `-mindepth` option causes commands not to be evaluated until the specified depth is reached.
This commit is contained in:
parent
05d8e2f6f8
commit
a95c2ed978
Notes:
sideshowbarker
2024-07-17 07:25:39 +09:00
Author: https://github.com/tcl3 Commit: https://github.com/SerenityOS/serenity/commit/a95c2ed978 Pull-request: https://github.com/SerenityOS/serenity/pull/21016
2 changed files with 69 additions and 3 deletions
|
@ -24,6 +24,12 @@ specified commands, a `-print` command is implicitly appended.
|
|||
|
||||
## Commands
|
||||
|
||||
* `-maxdepth n`: Do not descend more than `n` levels below each path given on
|
||||
the command line. Specifying `-maxdepth 0` has the effect of only evaluating
|
||||
each command line argument.
|
||||
* `-mindepth n`: Descend `n` levels below each path given on the command line
|
||||
before executing any commands. Specifying `-mindepth 1` has the effect of
|
||||
processing all files except the command line arguments.
|
||||
* `-type t`: Checks if the file is of the specified type, which must be one of
|
||||
`b` (for block device), `c` (character device), `d` (directory), `l` (symbolic
|
||||
link), `p` (FIFO), `f` (regular file), and `s` (socket).
|
||||
|
|
|
@ -33,6 +33,8 @@ bool g_follow_symlinks = false;
|
|||
bool g_there_was_an_error = false;
|
||||
bool g_have_seen_action_command = false;
|
||||
bool g_print_hyperlinks = false;
|
||||
Optional<u32> g_max_depth = {};
|
||||
Optional<u32> g_min_depth = {};
|
||||
|
||||
template<typename... Parameters>
|
||||
[[noreturn]] static void fatal_error(CheckedFormatString<Parameters...>&& fmtstr, Parameters const&... parameters)
|
||||
|
@ -167,6 +169,42 @@ private:
|
|||
}
|
||||
};
|
||||
|
||||
class MaxDepthCommand : public Command {
|
||||
public:
|
||||
MaxDepthCommand(char const* arg)
|
||||
{
|
||||
auto max_depth_string = StringView { arg, strlen(arg) };
|
||||
auto maybe_max_depth = max_depth_string.to_uint<u32>();
|
||||
if (!maybe_max_depth.has_value())
|
||||
fatal_error("-maxdepth: '{}' is not a valid non-negative integer", arg);
|
||||
|
||||
g_max_depth = maybe_max_depth.value();
|
||||
}
|
||||
|
||||
virtual bool evaluate(FileData&) const override
|
||||
{
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
class MinDepthCommand : public Command {
|
||||
public:
|
||||
MinDepthCommand(char const* arg)
|
||||
{
|
||||
auto min_depth_string = StringView { arg, strlen(arg) };
|
||||
auto maybe_min_depth = min_depth_string.to_uint<u32>();
|
||||
if (!maybe_min_depth.has_value())
|
||||
fatal_error("-mindepth: '{}' is not a valid non-negative integer", arg);
|
||||
|
||||
g_min_depth = maybe_min_depth.value();
|
||||
}
|
||||
|
||||
virtual bool evaluate(FileData&) const override
|
||||
{
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
class TypeCommand final : public Command {
|
||||
public:
|
||||
TypeCommand(char const* arg)
|
||||
|
@ -605,6 +643,14 @@ static OwnPtr<Command> parse_simple_command(Vector<char*>& args)
|
|||
|
||||
auto command = parse_simple_command(args).release_nonnull();
|
||||
return make<NotCommand>(move(command));
|
||||
} else if (arg == "-maxdepth"sv) {
|
||||
if (args.is_empty())
|
||||
fatal_error("-maxdepth: requires additional arguments");
|
||||
return make<MaxDepthCommand>(args.take_first());
|
||||
} else if (arg == "-mindepth"sv) {
|
||||
if (args.is_empty())
|
||||
fatal_error("-mindepth: requires additional arguments");
|
||||
return make<MinDepthCommand>(args.take_first());
|
||||
} else if (arg == "-type") {
|
||||
if (args.is_empty())
|
||||
fatal_error("-type: requires additional arguments");
|
||||
|
@ -746,9 +792,10 @@ static NonnullOwnPtr<Command> parse_all_commands(Vector<char*>& args)
|
|||
return make<AndCommand>(command.release_nonnull(), make<PrintCommand>());
|
||||
}
|
||||
|
||||
static void walk_tree(FileData& root_data, Command& command)
|
||||
static void walk_tree(FileData& root_data, Command& command, u32 depth = 0)
|
||||
{
|
||||
command.evaluate(root_data);
|
||||
if (!g_min_depth.has_value() || g_min_depth.value() <= depth)
|
||||
command.evaluate(root_data);
|
||||
|
||||
// We should try to read directory entries if either:
|
||||
// * This is a directory.
|
||||
|
@ -798,7 +845,20 @@ static void walk_tree(FileData& root_data, Command& command)
|
|||
false,
|
||||
dirent->d_type,
|
||||
};
|
||||
walk_tree(file_data, command);
|
||||
|
||||
bool should_increase_depth = false;
|
||||
if (g_max_depth.has_value() || g_min_depth.has_value()) {
|
||||
if (g_max_depth.has_value() && depth >= g_max_depth.value())
|
||||
return;
|
||||
|
||||
if (file_data.d_type == DT_UNKNOWN)
|
||||
file_data.ensure_stat();
|
||||
|
||||
if (file_data.d_type == DT_DIR)
|
||||
should_increase_depth = true;
|
||||
}
|
||||
|
||||
walk_tree(file_data, command, should_increase_depth ? depth + 1 : depth);
|
||||
}
|
||||
|
||||
if (errno != 0) {
|
||||
|
|
Loading…
Add table
Reference in a new issue