# Dig.glob and dot file behavior: subtle edge case?

**URL:** <https://forum.crystal-lang.org/t/dig-glob-and-dot-file-behavior-subtle-edge-case/8665>\
**Category:** Crystal Contrib\
**Created:** [January 22, 2026, 8:00pm UTC](https://forum.crystal-lang.org/t/dig-glob-and-dot-file-behavior-subtle-edge-case/8665 "2026-01-22T20:00:09Z")\
**Posts on this page:** 6\
**Page:** 1

<div class="post-metadata">

**Author:** ![trans](https://yyz2.discourse-cdn.com/flex036/user_avatar/forum.crystal-lang.org/trans/32/1255_2.png) [@trans](https://forum.crystal-lang.org/u/trans)\
**Post date:** [January 22, 2026, 8:00pm UTC](https://forum.crystal-lang.org/t/dig-glob-and-dot-file-behavior-subtle-edge-case/8665/1 "2026-01-22T20:00:09Z")

</div>

Ran into a small oddity with Dir.glob and how it matches dotfiles. Looked into it: _not matching_ hidden files is standard behavior and one has to use the option `dot_files` to get hidden file to match. Ok. However:

- `*` │ [“subdir”] - doesn’t match .hidden

- `*/` [“subdir/”, “.hidden/”] - DOES match .hidden/

This inconsistency is why \*\*/\*/.gitignore “works” - when \* is followed by /, it inexplicably matches dotfiles.

---

<div class="post-metadata">

**Author:** ![straight-shoota](https://yyz2.discourse-cdn.com/flex036/user_avatar/forum.crystal-lang.org/straight-shoota/32/36_2.png) [@straight-shoota](https://forum.crystal-lang.org/u/straight-shoota)\
**Post date:** [January 22, 2026, 10:05pm UTC](https://forum.crystal-lang.org/t/dig-glob-and-dot-file-behavior-subtle-edge-case/8665/2 "2026-01-22T22:05:08Z")

</div>

I don’t think I understand what your examples are supposed to mean. I can’t understand the notation.  
Could you perhaps clarify the cases in text?

---

<div class="post-metadata">

**Author:** ![bcardiff](https://yyz2.discourse-cdn.com/flex036/user_avatar/forum.crystal-lang.org/bcardiff/32/3_2.png) [@bcardiff](https://forum.crystal-lang.org/u/bcardiff)\
**Post date:** [January 22, 2026, 10:10pm UTC](https://forum.crystal-lang.org/t/dig-glob-and-dot-file-behavior-subtle-edge-case/8665/3 "2026-01-22T22:10:05Z")

</div>

This was motivated from the code that was removed in [Use match: :dot\_files for glob instead of workaround · trans/ignoreme@26a1914 · GitHub](https://github.com/trans/ignoreme/commit/26a1914ee48cce64da1dc2eeaec9228ad67788d5)

---

<div class="post-metadata">

**Author:** ![trans](https://yyz2.discourse-cdn.com/flex036/user_avatar/forum.crystal-lang.org/trans/32/1255_2.png) [@trans](https://forum.crystal-lang.org/u/trans)\
**Post date:** [January 22, 2026, 11:53pm UTC](https://forum.crystal-lang.org/t/dig-glob-and-dot-file-behavior-subtle-edge-case/8665/4 "2026-01-22T23:53:30Z")

</div>

```auto
Dir.glob("*") # does not match hidden paths (standard behavior)
Dir.glob("*/") # does match hidden paths  

```

---

<div class="post-metadata">

**Author:** ![zw963](https://yyz2.discourse-cdn.com/flex036/user_avatar/forum.crystal-lang.org/zw963/32/1623_2.png) [@zw963](https://forum.crystal-lang.org/u/zw963)\
**Post date:** [January 23, 2026, 3:35am UTC](https://forum.crystal-lang.org/t/dig-glob-and-dot-file-behavior-subtle-edge-case/8665/5 "2026-01-23T03:35:27Z")

</div>

Dir.glob(“\*/”) is match with sub-directory in current folder, even though it does seem a bit inconsistent, a directory is also a file technically.

---

<div class="post-metadata">

**Author:** ![straight-shoota](https://yyz2.discourse-cdn.com/flex036/user_avatar/forum.crystal-lang.org/straight-shoota/32/36_2.png) [@straight-shoota](https://forum.crystal-lang.org/u/straight-shoota)\
**Post date:** [January 23, 2026, 10:32am UTC](https://forum.crystal-lang.org/t/dig-glob-and-dot-file-behavior-subtle-edge-case/8665/6 "2026-01-23T10:32:52Z")

</div>

Ah, gotcha 👍  
This looks like a bug, actually. `*/` should _not_ match `.dir/`, just like `*` doesn’t match `.file`.

> <https://github.com/crystal-lang/crystal/issues/16603>
>
> A path component starting with a wildcard in \`Dir.glob\` should not match a dot f…ile.
> That is unless \[\`MatchOptions::DotFiles\`\](https://crystal-lang.org/api/1.19.1/File/MatchOptions.html#enum-members) is that. But that's not the case for the default behaviour (cf \[\`File::MatchOptions.glob\_default\`\](https://crystal-lang.org/api/1.19.1/File/MatchOptions.html#glob\_default-class-method)).
> 
> \`Dir.glob("\*")\` works exactly like that. And \`Dir.glob("\*/")\` should be expected to do the same. After all, it's just an additional filter to include only directories. But, \`\*/\` does in fact match directories whose name starts with at dot:
> 
> \`\`\`cr
> File.touch(".file")
> Dir.mkdir(".dir")
>  
> Dir.glob("\*") # =\> \[\]
> Dir.glob("\*/") # =\> \[".dir/"\] # This should be empty
> \`\`\`
> 
> \---
> 
> Add a :+1: \[reaction\] to \[issues you find important\].
> 
> \[reaction\]: https://github.blog/2016-03-10-add-reactions-to-pull-requests-issues-and-comments/
> \[issues you find important\]:
> https://github.com/crystal-lang/crystal/issues?q=is%3Aissue+is%3Aopen+sort%3Areactions-%2B1-desc
