From 4eba921d482fa35ee6edfa6fe3ed977a87b4fbdb Mon Sep 17 00:00:00 2001 From: Ariel Don Date: Sun, 11 Jul 2021 11:30:48 -0500 Subject: [PATCH] ls: Add option to list subdirectories recursively List subdirectories encountered using -R or --recursive flags with ls. --- Base/usr/share/man/man1/ls.md | 3 +++ Userland/Utilities/ls.cpp | 29 ++++++++++++++++++++++++----- 2 files changed, 27 insertions(+), 5 deletions(-) diff --git a/Base/usr/share/man/man1/ls.md b/Base/usr/share/man/man1/ls.md index edeecae4cc..6902976fb1 100644 --- a/Base/usr/share/man/man1/ls.md +++ b/Base/usr/share/man/man1/ls.md @@ -31,6 +31,7 @@ If no *path* argument is provided the current working directory is used. * `-o`, In long format, do not show group information * `-h`, `--human-readable`: Print human-readable sizes * `-K`, `--no-hyperlinks`: Disable hyperlinks +* `-R`, `--recursive`: List subdirectories recursively ## Arguments @@ -43,6 +44,8 @@ If no *path* argument is provided the current working directory is used. $ ls # List contents of working directory including hidden dot files $ ls -la +# List contents of working directory and its subdirectories +$ ls -R # List contents of /etc/ directory $ ls /etc # List contents of /etc/ directory including hidden dot files diff --git a/Userland/Utilities/ls.cpp b/Userland/Utilities/ls.cpp index d57630c58c..7db7b6b8d8 100644 --- a/Userland/Utilities/ls.cpp +++ b/Userland/Utilities/ls.cpp @@ -51,6 +51,7 @@ static bool flag_human_readable = false; static bool flag_sort_by_timestamp = false; static bool flag_reverse_sort = false; static bool flag_disable_hyperlinks = false; +static bool flag_recursive = false; static size_t terminal_rows = 0; static size_t terminal_columns = 0; @@ -88,7 +89,7 @@ int main(int argc, char** argv) return 1; } - Vector paths; + Vector paths; Core::ArgsParser args_parser; args_parser.set_general_help("List files in a directory."); @@ -106,6 +107,7 @@ int main(int argc, char** argv) args_parser.add_option(flag_hide_group, "In long format, do not show group information", nullptr, 'o'); args_parser.add_option(flag_human_readable, "Print human-readable sizes", "human-readable", 'h'); args_parser.add_option(flag_disable_hyperlinks, "Disable hyperlinks", "no-hyperlinks", 'K'); + args_parser.add_option(flag_recursive, "List subdirectories recursively", "recursive", 'R'); args_parser.add_positional_argument(paths, "Directory to list", "path", Core::ArgsParser::Required::No); args_parser.parse(argc, argv); @@ -129,9 +131,8 @@ int main(int argc, char** argv) return do_file_system_object_short(path); }; - if (paths.is_empty()) { + if (paths.is_empty()) paths.append("."); - } quick_sort(paths, [](const String& a, const String& b) { return a < b; @@ -142,11 +143,29 @@ int main(int argc, char** argv) for (size_t i = 0; i < paths.size(); i++) { auto path = paths[i]; + if (flag_recursive && Core::File::is_directory(path)) { + size_t subdirs = 0; + Core::DirIterator di(path, Core::DirIterator::SkipParentAndBaseDir); + + if (di.has_error()) { + status = 1; + fprintf(stderr, "%s: %s\n", path.characters(), di.error_string()); + } + + while (di.has_next()) { + String directory = di.next_full_path(); + if (Core::File::is_directory(directory) && !Core::File::is_link(directory)) { + ++subdirs; + paths.insert(i + subdirs, move(directory)); + } + } + } + bool show_dir_separator = paths.size() > 1 && Core::File::is_directory(path) && !flag_list_directories_only; if (show_dir_separator) { - printf("%s:\n", path); + printf("%s:\n", path.characters()); } - auto rc = do_file_system_object(path); + auto rc = do_file_system_object(path.characters()); if (rc != 0) status = rc; if (show_dir_separator && i != paths.size() - 1) {