Project

General

Profile

Misc #14905

Strange behavior in Dir.glob using ** operator

Added by trobinson (Trevor Robinson) 5 months ago. Updated 5 months ago.

Status:
Rejected
Priority:
Normal
Assignee:
-
[ruby-core:87895]

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?

History

#1 [ruby-core:87896] Updated by mame (Yusuke Endoh) 5 months 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"]

#2 [ruby-core:87913] Updated by trobinson (Trevor Robinson) 5 months 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.

#3 [ruby-core:87916] Updated by nobu (Nobuyoshi Nakada) 5 months ago

  • Status changed from Feedback to Rejected

It is same as zsh.

Also available in: Atom PDF