# Glob expansion in std?

**URL:** <https://internals.rust-lang.org/t/glob-expansion-in-std/6182>\
**Category:** libs\
**Created:** [November 7, 2017, 12:12pm UTC](https://internals.rust-lang.org/t/glob-expansion-in-std/6182 "2017-11-07T12:12:15Z")\
**Posts on this page:** 14\
**Page:** 1

<div class="post-metadata">

**Author:** ![kornel](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/kornel/32/2711_2.png) [@kornel](https://internals.rust-lang.org/u/kornel)\
**Post date:** [November 7, 2017, 12:12pm UTC](https://internals.rust-lang.org/t/glob-expansion-in-std/6182/1 "2017-11-07T12:12:15Z")

</div>

Rust’s stdlib includes a cross-platform abstraction for CLI arguments (`env::args`), but there’s a catch: Unix shells perform glob expansion, but Windows shell doesn’t (so `program file.*` instead of selecting files with any extension just passes one arg literally with `"*"` in it).

Even though _technically_ the glob expansion is done on a completely different level outside of the program, tools written for Unix rely on that and assume that’s always available. And I assumed that, and my program failed to support globs on Windows.

Can this be improved? Should Rust’s stdlib emulate glob expansion on Windows? (e.g. MinGW does that!)

* * *

**edit:** Solved: [https://crates.rs/crates/wild](https://crates.rs/crates/wild)

---

<div class="post-metadata">

**Author:** ![burntsushi](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/burntsushi/32/279_2.png) [@burntsushi](https://internals.rust-lang.org/u/burntsushi)\
**Post date:** [November 7, 2017, 12:58pm UTC](https://internals.rust-lang.org/t/glob-expansion-in-std/6182/2 "2017-11-07T12:58:11Z")

</div>

I think this should, at the very least, begin life as a crate. Indeed, this exact bug has been reported to ripgrep: [https://github.com/BurntSushi/ripgrep/issues/234](https://github.com/BurntSushi/ripgrep/issues/234)

Note that there are two versions of a solution here. One is to use the standard Windows API for resolving globs, while the other is to use one of our own globbing libraries (e.g., `glob` or `globset`). The former might be consistent with what behavior users expect, but AIUI, the Windows support for globs is not quite the same as the standard Unix globbing.

---

<div class="post-metadata">

**Author:** ![derekdreery](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/derekdreery/32/2632_2.png) [@derekdreery](https://internals.rust-lang.org/u/derekdreery)\
**Post date:** [November 7, 2017, 3:12pm UTC](https://internals.rust-lang.org/t/glob-expansion-in-std/6182/3 "2017-11-07T15:12:28Z")

</div>

There are 2 situations

1. Accepting glob args in an executable (I think this is the OP). For this I think it’s up to the user to perform expansion. There are shells in Windows that will do this. Maybe you could print a warning if you see a ? or \* in the path, but iirc these are valid paths on at least Linux.

2. If you are running a program as a subprocess, I think it’s up to you to do the globbing. This saves any confusion.

---

<div class="post-metadata">

**Author:** ![kornel](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/kornel/32/2711_2.png) [@kornel](https://internals.rust-lang.org/u/kornel)\
**Post date:** [November 9, 2017, 10:58pm UTC](https://internals.rust-lang.org/t/glob-expansion-in-std/6182/4 "2017-11-09T22:58:04Z")

</div>

There’s `/link setargv.obj` option in MSVC. Could Rust set that?

---

<div class="post-metadata">

**Author:** ![parkovski](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/parkovski/32/2730_2.png) [@parkovski](https://internals.rust-lang.org/u/parkovski)\
**Post date:** [November 9, 2017, 11:04pm UTC](https://internals.rust-lang.org/t/glob-expansion-in-std/6182/5 "2017-11-09T23:04:38Z")

</div>

PowerShell does this already, and it’s much more capable and user friendly than cmd. Wordy, sure, but a much better shell experience.

This is just my own personal opinion, but I really think languages should respect the default platform behaviors as much as possible. Per application, sure, it’s up to you. Even if you did set that though, it probably won’t work with the GNU tool chain so Rust would have to maintain a copy for that, and Windows paths are complicated so mimicking something from MS might be tricky.

---

<div class="post-metadata">

**Author:** ![kornel](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/kornel/32/2711_2.png) [@kornel](https://internals.rust-lang.org/u/kornel)\
**Post date:** [November 9, 2017, 11:57pm UTC](https://internals.rust-lang.org/t/glob-expansion-in-std/6182/6 "2017-11-09T23:57:50Z")

</div>

but the default behavior on Windows _is_ to have globs (e.g. `dir *.*` works [edit: `dir *`, too]). A command that accepts files as arguments, but doesn’t take globs, is broken from user perspective, even on Windows.

glob characters are not allowed in Windows filenames, so double expansion is not a problem, so AFAIK it wouldn’t affect powershell (i.e. powershell or any other shell can have super fancy expansion however it wants and pass it to a command, and the result will be exactly the same regardless whether the command has its own basic expansion or not).

---

<div class="post-metadata">

**Author:** ![parkovski](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/parkovski/32/2730_2.png) [@parkovski](https://internals.rust-lang.org/u/parkovski)\
**Post date:** [November 10, 2017, 6:13pm UTC](https://internals.rust-lang.org/t/glob-expansion-in-std/6182/7 "2017-11-10T18:13:20Z")

</div>

That’s cmd behavior. For powershell you only need one \*. I agree that in this case it’s pretty harmless - NT paths (`\\?\...`) can contain \*s, but as long as you only apply it to Win32 paths there’s no problem with \*. But they can have []s - how do you escape those? PowerShell I think does that expansion too, and you escape with the backtick, so I’d have to know if the program was written in Rust I have to double escape them, which breaks shell tab expansion for those files. Also what if I’m using bash or another POSIX shell on Windows 10? And are you giving Rust cmd, PowerShell, bash or some other style of expansion? Personally I think the best solution is just to not use cmd as your shell.

---

<div class="post-metadata">

**Author:** ![kornel](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/kornel/32/2711_2.png) [@kornel](https://internals.rust-lang.org/u/kornel)\
**Post date:** [November 10, 2017, 7:13pm UTC](https://internals.rust-lang.org/t/glob-expansion-in-std/6182/8 "2017-11-10T19:13:04Z")

</div>

> [@parkovski](#):
>
> I’d have to know if the program was written in Rust I have to double escape them

No, you can only assume you can't possibly know. The problem is not unique to Rust. You'd also need to know whether a program was compiled with MinGW, or compiled with MSVC with `setargv` on, or is a Go program using `path.Glob`, etc.

So Rust can't make it any worse for users of other shells — this problem _already exists for all Windows programs_. But Rust can at least make it less bad for users of the built-in cmd though.

> [@parkovski](#):
>
> Personally I think the best solution is just to not use cmd as your shell.

That's not for me to choose (IMHO the best solution is not to use Windows at all). But I get bug reports from users that my program worked as expected in MinGW-compiled version, and the Rust does not.

---

<div class="post-metadata">

**Author:** ![kornel](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/kornel/32/2711_2.png) [@kornel](https://internals.rust-lang.org/u/kornel)\
**Post date:** [November 10, 2017, 7:21pm UTC](https://internals.rust-lang.org/t/glob-expansion-in-std/6182/9 "2017-11-10T19:21:10Z")

</div>

I’d like to point out that it’s _impossible_ for Rust programs to handle globs correctly themselves via `env::args()`. That’s because the args are already split and unquoted in the form exposed by Rust’s stdlib, and the difference between `*` and `"*"` is lost.

So even if we agree that glob expansion does not belong to stdlib and is each app’s own problem, there still has to be something in the stdlib to expose unparsed raw arguments to allow apps to implement globs themselves.

---

<div class="post-metadata">

**Author:** ![retep998](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/retep998/32/729_2.png) [@retep998](https://internals.rust-lang.org/u/retep998)\
**Post date:** [November 12, 2017, 12:36am UTC](https://internals.rust-lang.org/t/glob-expansion-in-std/6182/10 "2017-11-12T00:36:54Z")

</div>

You can _trivially_ get the raw unparsed command line on Windows though. Just call `GetCommandLineW` and then you can parse it and do whatever you want with it. Unless you want something cross platform, but since this is specifically a problem you have with `cmd.exe`, which is exclusive to Windows, platform specific code isn’t the worst thing in this case.

---

<div class="post-metadata">

**Author:** ![kornel](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/kornel/32/2711_2.png) [@kornel](https://internals.rust-lang.org/u/kornel)\
**Post date:** [November 17, 2017, 3:26pm UTC](https://internals.rust-lang.org/t/glob-expansion-in-std/6182/11 "2017-11-17T15:26:17Z")

</div>

I've implemented this as a crate:

[https://lib.rs/crates/wild](https://lib.rs/crates/wild)

---

<div class="post-metadata">

**Author:** ![ExpHP](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/exphp/32/6208_2.png) [@ExpHP](https://internals.rust-lang.org/u/ExpHP)\
**Post date:** [November 17, 2017, 11:25pm UTC](https://internals.rust-lang.org/t/glob-expansion-in-std/6182/12 "2017-11-17T23:25:15Z")

</div>

Wrapping `env::args()` seems like a bad idea to me, as it will affect even arguments that aren’t supposed to be interpreted as filepaths. Unix users might be used to this, but are windows users?

It also seems like a breeding ground for double-expansion issues, if you were writing a program that takes another as a command (like `time`).

---

<div class="post-metadata">

**Author:** ![kornel](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/kornel/32/2711_2.png) [@kornel](https://internals.rust-lang.org/u/kornel)\
**Post date:** [November 18, 2017, 12:38am UTC](https://internals.rust-lang.org/t/glob-expansion-in-std/6182/13 "2017-11-18T00:38:25Z")

</div>

From my unix experience it’s never a problem that non-file arg is interpreted as a path glob (only the other way around is common, but globs don’t affect that). You’d have to write an unquoted arg with glob characters _and_ have a file in the current directory with an unusual arg-like name like `--foo=` that matches the glob. In theory it can happen, but in practice it doesn’t. There are _so many_ much messed up things about cmd.exe that this isn’t even high on the list.

Glob metacharacters are forbidden in all filenames on Windows, so double expansion is impossible.

---

<div class="post-metadata">

**Author:** ![system](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/system/32/14092_2.png) [@system](https://internals.rust-lang.org/u/system)\
**Post date:** [March 25, 2019, 8:29am UTC](https://internals.rust-lang.org/t/glob-expansion-in-std/6182/14 "2019-03-25T08:29:12Z")

</div>

Closed on March 25, 2019, 8:29am UTC

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.
