shelljs / shx

Portable Shell Commands for Node
MIT License
1.72k stars 44 forks source link

Recursive globbing (./**/) works differently depending on OS #190

Closed leonheess closed 2 years ago

leonheess commented 3 years ago

Consider this command: shx cp -r ./src/**/*.js .. It is copying all .js-files from ./src and its sub-directories into .. On Windows 10 it will also consider every .js-file inside src but on Debian it will only copy files from sub-directories of src but not src itself.

Windows 10:

src/
├── sub-dir/
│   ├── will-be-copied.js
├── will-also-be-copied.js

Debian:

src/
├── sub-dir/
│   ├── will-be-copied.js
├── will-NOT-be-copied.js
nfischer commented 3 years ago

What is the behavior of shx cp -r "./src/**/*.js" . (glob is wrapped in quotes)? Is that the same on both operating systems?

leonheess commented 2 years ago

What is the behavior of shx cp -r "./src/**/*.js" . (glob is wrapped in quotes)? Is that the same on both operating systems?

No, also different. Only happens if it's called with npm or yarn

nfischer commented 2 years ago

but on Debian it will only copy files from sub-directories of src but not src itself.

I cannot reproduce this on my Ubuntu machine:

$ mkdir src
$ touch src/1.js
$ shx cp -r ./src/**/*.js .
$ ls
1.js  src

I think this is more likely a problem with the shell on your Debian machine. Maybe you have a really old version of Bash shell which doesn't support the ** syntax? I'm also not sure what you mean by "Only happens if it's called with npm or yarn" but if you're talking about npm's "package scripts" feature, then this may also point to the same problem because that uses the system's /bin/sh shell (source).

Regardless, this seems unlikely to be a problem with shx or shelljs. Unix shells perform glob-expansion before invoking the command. This means that by the time shx is invoked, the shell has already decided the full list of matching files and provided those explicitly to our process (in your example, this looks like shx cp -r ./src/sub-dir/will-be-copied.js ./src/will-NOT-be-copied.js).

You can work around this by forcing your shell to not perform glob-expansion, which will allow shx to perform the expansion itself. In the commandline this looks likeshx cp -r "./src/**/*.js" . (note the placement of the double-quote characters). In package.json this looks like:

{
  "scripts": {
    "name-of-script": "shx cp -r \"./src/**/*.js\" ."
  }
}
leonheess commented 2 years ago

Not sure what to tell you. I have a npm package script that is shx cp -r ./src/**/*.js . and if I run in on my Windows machine it does something different than it does in the Ubuntu Azure pipeline (as described in the issue description).

I had to rewrite to shx cp ./src/*.js . && shx cp ./src/sub-dir/*.js . for it to work identical on both machines.

For the pipeline I am using the Azure ubuntu-latest image.

nfischer commented 2 years ago

Not sure what to tell you. I have a npm package script that is shx cp -r ./src/**/*.js .

I believe you have that script, but did you see my recommended workaround about wrapping the glob expansion in double quote characters (")?

leonheess commented 2 years ago

I'll check and let you know :)