Skip to content

Feature Request: Allow dir_ls glob/regex patterns to ignore the supplied path #512

Open

Description

@orgadish

dir_ls glob/regex patterns act on the whole path, including what was passed by path. Often this can be accidentally misleading since the folder path itself contains a pattern (maybe even accidentally) that breaks the intended logic.

Request: it would be great if there were an argument to dir_ls to ignore the part of the path that was already supplied in path (effectively filtering only on the relative path).

Simple reprex:

temp <- tempfile("T Cell") |> fs::dir_create()

tryCatch({
   good_path <- fs::path(temp, "T Cell Data.csv")
   bad_path <-  fs::path(temp, "Other Data.csv")
   
   readr::write_csv(data.frame(), good_path)
   readr::write_csv(data.frame(), bad_path)
   
   ls_result <- fs::dir_ls(temp, glob="*T Cell*.csv")
   
   message("good_path found: ", good_path %in% ls_result)
   message("bad_path found: ", bad_path %in% ls_result)
},
finally = fs::dir_delete(temp) 
)
#> good_path found: TRUE
#> bad_path found: TRUE

Created on 2026-03-31 with reprex v2.1.1

Simple implementation extending current dir_ls with argument filter_on_relative_path.

dir_ls <- function (path = ".", all = FALSE, recurse = FALSE, type = "any", 
    glob = NULL, regexp = NULL, invert = FALSE, fail = TRUE, filter_on_relative_path = FALSE,
    ..., recursive) 
{
    assert_no_missing(path)
    if (!missing(recursive)) {
        recurse <- recursive
        warning("`recursive` is deprecated, please use `recurse` instead", 
            immediate. = TRUE, call. = FALSE)
    }
    old <- path_expand(path)
    files <- as.character(dir_map(old, identity, all, recurse, 
        type, fail))

    # Simple case (same as existing)
    if (!filter_on_relative_path)
        return(path_filter(files, glob, regexp, invert = invert, ...))

   # Filter on relative path only.
   rel_files <- fs::path_rel(files, start=old)
   
   files[match(fs::path_filter(rel_files, glob, regexp, invert = invert, ...), rel_files)]
}

Activity

  1. orgadish commented on Apr 1, 2026

    @orgadish
    ContributorAuthor

    If approved, I'm happy to put in a PR with the implementation above (and associated testing), given an agreed name for the argument (perhaps just relative?)

  2. arnaudgallou commented on Jul 6, 2026

    @arnaudgallou

    I've the same request. dir_ls(regex =) seems to match against the full path as opposed to list.files(pattern =) that matches against the actual elements of a path. The latter is more convenient and less confusing because it makes it easy to avoid matching undesired files or directories using ^ (rather than /).

    dir <- fs::path_temp()
    dir <- fs::dir_create(dir, "fs")
    
    for (file in c("foo", "barfoo")) {
      fs::file_create(dir, file)
    }
    
    dir |> 
      fs::dir_ls(regexp = "foo$", recurse = TRUE) |> 
      fs::path_file() |> 
      print()
    #> [1] "barfoo" "foo"
    
    dir |> 
      fs::dir_ls(regexp = "^foo$", recurse = TRUE) |> 
      fs::path_file() |> 
      print()
    #> character(0)
    
    dir |> 
      list.files(pattern = "^foo$", recursive = TRUE) |> 
      print()
    #> [1] "foo"

    Created on 2026-07-06 with reprex v2.1.1

    I'd prefer dir_list() to behave like list.files() here. Also, I find it confusing that dir_ls(regexp = "^foo$") returns character(0). It would be useful to have a hint explaining why there's no match because the regexp is valid and the file exists.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions