Misc #14905
closedStrange behavior in Dir.glob using ** operator
Description
Hello,
I didn't want to report this as a bug because I'm not sure if it's intentional or not. The documentation didn't say either way. The **
operator appears to work somewhat strangely when used in certain contexts.
An example setup to trigger the odd behavior looks something like this:
human_records
├ person1 ─ records.yml
└ person2 ─ other_records.yml
cloud_records
├ AWS ┬ project1 ─ records.yml
│ └ project2 ─ records.yml
└ Azure ─ azproj1 ─ records.yml
Though the documentation doesn't say to do this, because of my experience with other globbing libraries, I did the following:
Dir.glob("human_records/**.{yml,yaml}")
# => ["human-records/person1/records.yml", "human_records/person2/other_records.yml"]
Dir.glob("cloud_records/**.{yml,yaml}")
# => []
So using **
like this works if there is only one level of folders between the root and the target files, as if the glob was "records/*/*.{yml,yaml}"
.
This seems like undefined behavior, so I thought I would bring it to your attention. If a change isn't a good solution to this, would a note in the documentation about undefined behavior around **
be warranted?
Updated by mame (Yusuke Endoh) almost 6 years ago
- Status changed from Open to Feedback
I cannot reproduce the issue on Linux. What OS are you using?
$ ruby -v
ruby 2.5.1p57 (2018-03-29 revision 63029) [x86_64-linux]
$ find human_records/ cloud_records/ -type f
human_records/person2/other_records.yml
human_records/person1/records.yml
cloud_records/AWS/project2/records.yml
cloud_records/AWS/project1/records.yml
cloud_records/Azure/azproj1/records.yml
$ ruby -e 'p Dir.glob("human_records/**.{yml,yaml}")'
[]
$ ruby -e 'p Dir.glob("cloud_records/**.{yml,yaml}")'
[]
I think this pattern depends on a behavior of typical shells. I'm unsure about the spec, but as far as I know, **
is not used as a part of file name, but as a pattern that matches zero or more directories. So you may want to use **/*.yml
.
$ ruby -e 'p Dir.glob("human_records/**/*.{yml,yaml}")'
["human_records/person2/records.yml", "human_records/person1/other_records.yml"]
$ ruby -e 'p Dir.glob("cloud_records/**/*.{yml,yaml}")'
["cloud_records/AWS/project2/records.yml", "cloud_records/AWS/project1/records.yml", "cloud_records/Azure/azproj1/records.yml"]
Updated by trobinson (Trevor Robinson) almost 6 years ago
Oops, sorry about that! In my efforts to anonymize the example, I broke it.
It's actually more like this:
human_records
├ project1 ─ records.yml
└ common ┬ records_one.yml
└ records_two.yml
cloud_records
├ AWS ┬ project1 ─ records.yml
│ └ project2 ─ records.yml
└ Azure ─ azproj1 ─ records.yml
Dir.glob("human_records/common/**.{yml,yaml}")
# => ["human-records/common/records.yml", "human_records/common/other_records.yml"]
Dir.glob("cloud_records/AWS/**.{yml,yaml}")
# => []
Sorry for the earlier erroneous description-- the weirdness is that **
acts like *
when used at the filename level.
Updated by nobu (Nobuyoshi Nakada) almost 6 years ago
- Status changed from Feedback to Rejected
It is same as zsh.