This repository has been archived by the owner. It is now read-only.

`npm run-script` doesn't work on windows when the script contains multiple commands #4040

Closed
balupton opened this Issue Oct 25, 2013 · 19 comments

Comments

Projects
None yet
@balupton

If I have:

{
  "scripts": {
    "test": "node ./out/test/everything-test.js",
    "prepublish": "./node_modules/.bin/projectz compile; npm test"
  }
}

And I run npm run-script prepublish on windows, no script will execute.

C:\Users\Benjamin\Documents\GitHub\ambi [dev-cakefile-replace +0 ~6 -0]> npm run-script prepublish

> ambi@2.1.4 prepublish C:\Users\Benjamin\Documents\GitHub\ambi
> node ./node_modules/projectz/bin/projectz compile; npm test

If I run the scripts manually, it works:

C:\Users\Benjamin\Documents\GitHub\ambi [dev-cakefile-replace +0 ~6 -0]> node ./node_modules/projectz/bin/projectz compile; npm test
info: Initialising project
info: Initialised project
info: Loading changes
info: Loaded 2 contributors from bevry/ambi repository
info: Loaded changes
info: Writing changes...
info: Writing package file: C:\Users\Benjamin\Documents\GitHub\ambi\package.json
info: Writing package file: C:\Users\Benjamin\Documents\GitHub\ambi\bower.json
info: Writing package file: C:\Users\Benjamin\Documents\GitHub\ambi\component.json
info: Skipping package file: jquery
info: Writing readme file: readme
info: Writing readme file: history
info: Skipping readme file: contributing
info: Skipping readme file: backers
info: Writing readme file: license
info: Wrote changes
info: Saved changes

> ambi@2.1.4 test C:\Users\Benjamin\Documents\GitHub\ambi
> node ./out/test/everything-test.js

ambi
ambi > should handle result on successful synchronous functions
ambi > should handle result on successful synchronous functions OK
ambi > should handle result on successful asynchronous functions
ambi > should handle result on successful asynchronous functions OK
ambi > should handle returned errors on unsuccessful synchronous functions
ambi > should handle returned errors on unsuccessful synchronous functions OK
ambi > should handle callbacked errors on unsuccessful asynchronous functions
ambi > should handle callbacked errors on unsuccessful asynchronous functions OK
ambi > should ignore returned errors on successfull asynchronous functions
ambi > should ignore returned errors on successfull asynchronous functions OK
ambi > should ignore returned errors on unsuccessful asynchronous functions
ambi > should ignore returned errors on unsuccessful asynchronous functions OK
ambi > should NOT handle thrown errors on unsuccessful synchronous functions
ambi > should NOT handle thrown errors on unsuccessful synchronous functions OK
ambi > should NOT handle thrown errors on unsuccessful asynchronous functions
ambi > should NOT handle thrown errors on unsuccessful asynchronous functions OK
ambi > should NOT handle asynchronous thrown errors on unsuccessful asynchronous functions
ambi > should NOT handle asynchronous thrown errors on unsuccessful asynchronous functions OK
ambi OK

9/9 tests ran successfully, everything passed
C:\Users\Benjamin\Documents\GitHub\ambi [dev-cakefile-replace +0 ~6 -0]>
@balupton

This comment has been minimized.

Show comment
Hide comment
@balupton

balupton Oct 25, 2013

Hrmmm, running the joined commands via child_process.exec doesn't work either:

C:\Users\Benjamin\Documents\GitHub\ambi [dev-cakefile-replace +0 ~6 -0]> node -e "require('child_process').exec('node ./node_modules/projectz/bin/projectz compile; npm test', {env:process.env, cwd:process.cwd()}, console.log)"
null '' ''

Hrmmm, running the joined commands via child_process.exec doesn't work either:

C:\Users\Benjamin\Documents\GitHub\ambi [dev-cakefile-replace +0 ~6 -0]> node -e "require('child_process').exec('node ./node_modules/projectz/bin/projectz compile; npm test', {env:process.env, cwd:process.cwd()}, console.log)"
null '' ''
@bear

This comment has been minimized.

Show comment
Hide comment
@bear

bear Oct 25, 2013

npm script runs are handled on linux/osx by calling sh so I would imagine on windows it is done by calling cmd.exe (or whatever your environment has defined) and as such I can't imagine you could expect ; to work across all OS's

even on linux I have trouble getting complex command lines to survive the journey thru nodejs and npm's script runs - so I just got used to creating wrapper bash scripts and letting the shebang line tell sh that it needs to spawn bash

i'm wondering if you can do something similar - create a foo.sh script and see if powershell's linux-like shell handling lets you get your commands run

bear commented Oct 25, 2013

npm script runs are handled on linux/osx by calling sh so I would imagine on windows it is done by calling cmd.exe (or whatever your environment has defined) and as such I can't imagine you could expect ; to work across all OS's

even on linux I have trouble getting complex command lines to survive the journey thru nodejs and npm's script runs - so I just got used to creating wrapper bash scripts and letting the shebang line tell sh that it needs to spawn bash

i'm wondering if you can do something similar - create a foo.sh script and see if powershell's linux-like shell handling lets you get your commands run

@isaacs

This comment has been minimized.

Show comment
Hide comment
@isaacs

isaacs Oct 27, 2013

Member

Commands are passed verbatim to either cmd or sh. Note that on OS X and some Linuxes, sh is actually bash with the (misnamed!) POSIXLY_CORRECT flag turned on.

Keep your command lines simple. A bash script won't work on Windows, for obvious reasons. Write a node program, or better yet, just don't use an install command. Presumably your prepublish script could just be written as a Node program, and run npm test as a spawn at the end.

Also, never ever write ./node_modules/.bin/ in your scripts. Seriously, that should just throw. What if the dep is somewhere else, installed globally, or as a parent's dep? npm puts ./node_modules/.bin in the PATH environ for a reason. Do not tightly couple to non-portable platform-specific paths! </rant>

Member

isaacs commented Oct 27, 2013

Commands are passed verbatim to either cmd or sh. Note that on OS X and some Linuxes, sh is actually bash with the (misnamed!) POSIXLY_CORRECT flag turned on.

Keep your command lines simple. A bash script won't work on Windows, for obvious reasons. Write a node program, or better yet, just don't use an install command. Presumably your prepublish script could just be written as a Node program, and run npm test as a spawn at the end.

Also, never ever write ./node_modules/.bin/ in your scripts. Seriously, that should just throw. What if the dep is somewhere else, installed globally, or as a parent's dep? npm puts ./node_modules/.bin in the PATH environ for a reason. Do not tightly couple to non-portable platform-specific paths! </rant>

@isaacs isaacs closed this Oct 27, 2013

@rlidwka

This comment has been minimized.

Show comment
Hide comment
@rlidwka

rlidwka Oct 28, 2013

Contributor

What if the dep is somewhere else, installed globally, or as a parent's dep?

  1. As far as I know, if a dependency is installed globally or elsewhere, npm install won't find it and would install it locally anyway. So this command line would work.
  2. As far as I know, npm run-script doesn't handle parent's dep case correctly as well, so it's the same deal in this case.

So the only case when ./node_modules/.bin/ is actually worse than npm run-script is when a dependency is installed both as a parent and globally. Hmm, I suppose you're right though.

Contributor

rlidwka commented Oct 28, 2013

What if the dep is somewhere else, installed globally, or as a parent's dep?

  1. As far as I know, if a dependency is installed globally or elsewhere, npm install won't find it and would install it locally anyway. So this command line would work.
  2. As far as I know, npm run-script doesn't handle parent's dep case correctly as well, so it's the same deal in this case.

So the only case when ./node_modules/.bin/ is actually worse than npm run-script is when a dependency is installed both as a parent and globally. Hmm, I suppose you're right though.

@plato-cambrian

This comment has been minimized.

Show comment
Hide comment
@plato-cambrian

plato-cambrian Sep 10, 2014

I want to both run bower install and update my webdriver during postinstall; with the same package.json usable on both windows and linux.

Is there way that will let both these scripts run without making a new file? Here's what I am doing now:
"postinstall": "node node_modules/bower/bin/bower install; node node_modules/protractor/bin/webdriver-manager update"

The relative paths are because I don't want to assume bower or protractor are installed globally.

I want to both run bower install and update my webdriver during postinstall; with the same package.json usable on both windows and linux.

Is there way that will let both these scripts run without making a new file? Here's what I am doing now:
"postinstall": "node node_modules/bower/bin/bower install; node node_modules/protractor/bin/webdriver-manager update"

The relative paths are because I don't want to assume bower or protractor are installed globally.

@othiym23 othiym23 added the support label Sep 21, 2014

@maranomynet

This comment has been minimized.

Show comment
Hide comment
@maranomynet

maranomynet Oct 20, 2014

@balupton, this should work:

"prepublish": "./node_modules/.bin/projectz compile && npm test"

The only 'catch' is that the second command (npm test) won't run if the first one fails.

@balupton, this should work:

"prepublish": "./node_modules/.bin/projectz compile && npm test"

The only 'catch' is that the second command (npm test) won't run if the first one fails.

@othiym23

This comment has been minimized.

Show comment
Hide comment
@othiym23

othiym23 Oct 21, 2014

Contributor

@maranomynet the ./node_modules/.bin/ part of that path is redundant. As @isaacs says, npm run-script takes care of putting node_modules/.bin on the PATH for you.

Contributor

othiym23 commented Oct 21, 2014

@maranomynet the ./node_modules/.bin/ part of that path is redundant. As @isaacs says, npm run-script takes care of putting node_modules/.bin on the PATH for you.

@maranomynet

This comment has been minimized.

Show comment
Hide comment
@maranomynet

maranomynet Oct 21, 2014

oh, I assumed the semi-colon was part of his problem, because on Windows command-line semicolon delimits parameters, instead of operations.

I stumbled upon this post as I was dealing with two-step package.json scripts not running on Windows, because of this semi-colon issue.

As soon as I changed the semi-colon to & (windows-only replacement for ;) or && (conditional) everything started running smoothly. And && works cross-platform.

(http://www.microsoft.com/resources/documentation/windows/xp/all/proddocs/en-us/ntcmds_shelloverview.mspx?mfr=true)

oh, I assumed the semi-colon was part of his problem, because on Windows command-line semicolon delimits parameters, instead of operations.

I stumbled upon this post as I was dealing with two-step package.json scripts not running on Windows, because of this semi-colon issue.

As soon as I changed the semi-colon to & (windows-only replacement for ;) or && (conditional) everything started running smoothly. And && works cross-platform.

(http://www.microsoft.com/resources/documentation/windows/xp/all/proddocs/en-us/ntcmds_shelloverview.mspx?mfr=true)

@gustavnikolaj gustavnikolaj referenced this issue in gotwarlost/istanbul Dec 16, 2014

Closed

Any way to integrate with cucumber? #287

Parad0x0217 added a commit to Parad0x0217/nba that referenced this issue Mar 29, 2015

@Parad0x0217 Parad0x0217 referenced this issue in bttmly/nba Mar 29, 2015

Merged

Fix for building on Windows #10

@harriha harriha referenced this issue in dwyl/learn-json-web-tokens Jun 21, 2015

Merged

Clean-up npm scripts (and make them work on Windows) #30

Jeff-Lewis added a commit to Jeff-Lewis/blanket that referenced this issue Dec 1, 2015

Made 'npm test' script work on Windows.
- When running npm scripts, npm puts ./node_modules/.bin in the path so referencing hard coded ./node_modules/mocha/bin/mocha is not recommended nor is it cross platform. See npm/npm#4040 (comment)
- Updated mocha to 2.3.4

@dotfold dotfold referenced this issue in jshanson7/babel-resolver Dec 30, 2015

Merged

Fix windows path separator #3

cjblomqvist added a commit to cjblomqvist/generator-derby that referenced this issue Jan 5, 2016

@Zougi

This comment has been minimized.

Show comment
Hide comment
@Zougi

Zougi Apr 12, 2016

&& do not work on Powershell
&& is not cross platform.

Zougi commented Apr 12, 2016

&& do not work on Powershell
&& is not cross platform.

@othiym23

This comment has been minimized.

Show comment
Hide comment
@othiym23

othiym23 Apr 12, 2016

Contributor

npm does not run package scripts using PowerShell on Windows, @Zougi. cmd.exe, which npm does use, doesn't have the exact same semantics for && (it executes the second command regardless of the success of the first), but it does work to string together multiple commands on a line.

Contributor

othiym23 commented Apr 12, 2016

npm does not run package scripts using PowerShell on Windows, @Zougi. cmd.exe, which npm does use, doesn't have the exact same semantics for && (it executes the second command regardless of the success of the first), but it does work to string together multiple commands on a line.

@Zougi

This comment has been minimized.

Show comment
Hide comment
@Zougi

Zougi Apr 13, 2016

Hi @othiym23. I did a re-test, you are right. I thought npm uses the shell from where it is called. Thanks for the clarification.

Zougi commented Apr 13, 2016

Hi @othiym23. I did a re-test, you are right. I thought npm uses the shell from where it is called. Thanks for the clarification.

miketmoore added a commit to miketmoore/baltimore-vacant-buildings that referenced this issue May 18, 2016

Remove full path in npm scripts
See issue npm/npm#4040, comment by @othiym23
npm-run-script adds ./node_modules/.bin on the PATH

miketmoore added a commit to miketmoore/baltimore-vacant-buildings that referenced this issue May 27, 2016

Remove full path in npm scripts
See issue npm/npm#4040, comment by @othiym23
npm-run-script adds ./node_modules/.bin on the PATH

@jmfolds jmfolds referenced this issue in Esri/esri-leaflet-geocoder Aug 3, 2016

Closed

npm start fails on windows #131

@RyanCCollins RyanCCollins referenced this issue in scalable-react/scalable-react-boilerplate Aug 25, 2016

Closed

Got code ELIFECYCLE after running 'npm run dev' #22

@otanim otanim referenced this issue in iteratehackerspace/iteratehackerspace.github.io Oct 4, 2016

Merged

"npm run build_site" support for Winows; .gitignore file update #7

cheshire137 added a commit to cheshire137/gh-notifications-snoozer that referenced this issue Oct 16, 2016

@tylersticka tylersticka referenced this issue in cloudfour/drizzle-builder Nov 1, 2016

Closed

(Windows) Test and build scripts fail #98

@clarkbw clarkbw referenced this issue in devtools-html/debugger.html Jan 25, 2017

Merged

don't use ./node_modules/.bin/ in package.json #1857

2 of 2 tasks complete

@nucliweb nucliweb referenced this issue in mozdevs/js-for-gamedev Feb 23, 2017

Open

Fallo al generar el ebook #11

@baderas baderas referenced this issue in ultimate-comparisons/ultimate-comparison-BASE Mar 1, 2017

Closed

Not working on Windows 10 #12

@usergenic

This comment has been minimized.

Show comment
Hide comment
@usergenic

usergenic Mar 29, 2017

FWIW I just do this in my npm scripts to get them to work on windows AND linux/mac:

"something": "sh -c \"whatever | this && works\""

FWIW I just do this in my npm scripts to get them to work on windows AND linux/mac:

"something": "sh -c \"whatever | this && works\""
@Noxxys

This comment has been minimized.

Show comment
Hide comment
@Noxxys

Noxxys Apr 5, 2017

sh is not recognized on Windows

Noxxys commented Apr 5, 2017

sh is not recognized on Windows

@usergenic

This comment has been minimized.

Show comment
Hide comment
@usergenic

usergenic Apr 10, 2017

@Noxxys, which version of windows? I was only using a Windows 10 server to test.

@Noxxys, which version of windows? I was only using a Windows 10 server to test.

@Noxxys

This comment has been minimized.

Show comment
Hide comment
@Noxxys

Noxxys Apr 10, 2017

I'm using Windows 10, but it will be the same on Windows 7 and 8.1. sh is a Unix program, not installed on Windows unless you use a special shell.

Noxxys commented Apr 10, 2017

I'm using Windows 10, but it will be the same on Windows 7 and 8.1. sh is a Unix program, not installed on Windows unless you use a special shell.

@kurtmilam

This comment has been minimized.

Show comment
Hide comment
@kurtmilam

kurtmilam Apr 12, 2017

@usergenic: Thanks for the tip.
@Noxxys: I'm using this console emulator on Windows 10. 'sh' is recognized if I call it from a mintty or bash shell in the emulator. Just FYI for anyone looking for a reasonably easy solution to this issue.

@usergenic: Thanks for the tip.
@Noxxys: I'm using this console emulator on Windows 10. 'sh' is recognized if I call it from a mintty or bash shell in the emulator. Just FYI for anyone looking for a reasonably easy solution to this issue.

@balupton

This comment has been minimized.

Show comment
Hide comment
@balupton

balupton Apr 16, 2017

wouldn't https://msdn.microsoft.com/en-us/commandline/wsl/install_guide solve this without having to change anything in our packages?

for an update from my side, I've just gone and used npm scripts for everything https://github.com/bevry/base/blob/7f88b7dd5994d0637595b39f92bb168bc82695b9/package.json#L85-L105 with bash conventions - and now that every OS that devs use has bash, I'm happy to just say to our devs use bash when running the npm scripts - I haven't yet tried this on windows, but I'd imagine it would work - it works on non-standard login shells like fish on mac and linux (fish doesn't use && but instead uses ; and), so it is good that the commands still seem executed by bash as Isaac mentioned earlier)


If it doesn't work on windows due to:

Commands are passed verbatim to either cmd or sh. Note that on OS X and some Linuxes, sh is actually bash with the (misnamed!) POSIXLY_CORRECT flag turned on.

Then it would be good if npm preferred bash or sh over cmd - by checking if bash or sh exists, and if it doesn't, then use cmd

balupton commented Apr 16, 2017

wouldn't https://msdn.microsoft.com/en-us/commandline/wsl/install_guide solve this without having to change anything in our packages?

for an update from my side, I've just gone and used npm scripts for everything https://github.com/bevry/base/blob/7f88b7dd5994d0637595b39f92bb168bc82695b9/package.json#L85-L105 with bash conventions - and now that every OS that devs use has bash, I'm happy to just say to our devs use bash when running the npm scripts - I haven't yet tried this on windows, but I'd imagine it would work - it works on non-standard login shells like fish on mac and linux (fish doesn't use && but instead uses ; and), so it is good that the commands still seem executed by bash as Isaac mentioned earlier)


If it doesn't work on windows due to:

Commands are passed verbatim to either cmd or sh. Note that on OS X and some Linuxes, sh is actually bash with the (misnamed!) POSIXLY_CORRECT flag turned on.

Then it would be good if npm preferred bash or sh over cmd - by checking if bash or sh exists, and if it doesn't, then use cmd

@rainabba

This comment has been minimized.

Show comment
Hide comment
@rainabba

rainabba May 4, 2017

I'm dealing with the same issue. "&&" is what I'd normally use on windows, but it's not supported on POSIX. With Windows 10 1703 and WSL, I can use the sh trick that @usergenic mentioned, but my Windows Servers aren't running WSL so I'm still looking for a solution.

Why not just allow scripts (in package.json) to be string OR Array and when an array, parse it and execute each?

rainabba commented May 4, 2017

I'm dealing with the same issue. "&&" is what I'd normally use on windows, but it's not supported on POSIX. With Windows 10 1703 and WSL, I can use the sh trick that @usergenic mentioned, but my Windows Servers aren't running WSL so I'm still looking for a solution.

Why not just allow scripts (in package.json) to be string OR Array and when an array, parse it and execute each?

IDragonfire added a commit to IDragonfire/devour that referenced this issue May 8, 2017

@IDragonfire IDragonfire referenced this issue in twg/devour May 8, 2017

Merged

Now also runs under windows #80

IDragonfire added a commit to IDragonfire/devour that referenced this issue May 8, 2017

@collinsauve collinsauve referenced this issue in tshaddix/react-chrome-redux Jun 13, 2017

Merged

allow lint/tests to be run on windows bash #83

@sethhays sethhays referenced this issue in philopian/AppSeed Jun 16, 2017

Closed

npm start -s is not working on windows machines #1

@corydeppen corydeppen referenced this issue in pburtchaell/react-notification Jun 17, 2017

Merged

Remove `npm bin` for Windows suport #129

@DaveMonag DaveMonag referenced this issue in hotforfeature/origami Jul 12, 2017

Closed

How do you run the demo? #45

@vajahath vajahath referenced this issue in vajahath/generator-ts-np Aug 19, 2017

Closed

Remove redundant parts from npm scripts #10

@neoziro neoziro referenced this issue in gaearon/react-hot-loader Oct 12, 2017

Closed

This project is dead and you're killing it. #656

@Vamoss Vamoss referenced this issue in networked-aframe/networked-aframe Nov 10, 2017

Open

System cannot find the path specified? #4

@1natsu172 1natsu172 referenced this issue in dideler/toggle-youtube-comments Feb 16, 2018

Merged

Compress extension using minify JS solution by node.js #37

@brownieboy

This comment has been minimized.

Show comment
Hide comment
@brownieboy

brownieboy Apr 27, 2018

Essentially, this is boolean logic. So you can use that boolean logic to force the second script to run, even if the first script fails, and yes it works on Windows (where the semi-colon syntax doesn't work). Here's what I originally had in the scripts property of my package.json:

"scripts": {
    testRun: "node ./runtest.js && node ./runreports.js",

In this case, runreports.js would only run if runjest.js completed succesfully - i.e. didn't crash with exit code="1" (or whatever). That's because it's a logical AND. So I changed it to this to a boolean OR, like so:

"scripts": {
    testRun "node ./runtest.js || node ./runreports.js",

Now I had the opposite problem: runreports.js only ran if runtest.js did crash!

The way to force runreports.js to always run is to ensure that the preceding condition always results in a boolean true. In boolean logic something OR true always results in true, i.e:

true || true = true
true || false = true
false || true = true

Applying that logic to my package.json script:

"scripts": {
    "(node ./runtest.js || true) && node ./runreports.js",

By wrapping he first script call with in some brackets and the ORing it with a true, the result of that bracketed section must always be true, no matter what the runtest.js script does. So runreports.js will always run.

It works for me on Windows anyway.

brownieboy commented Apr 27, 2018

Essentially, this is boolean logic. So you can use that boolean logic to force the second script to run, even if the first script fails, and yes it works on Windows (where the semi-colon syntax doesn't work). Here's what I originally had in the scripts property of my package.json:

"scripts": {
    testRun: "node ./runtest.js && node ./runreports.js",

In this case, runreports.js would only run if runjest.js completed succesfully - i.e. didn't crash with exit code="1" (or whatever). That's because it's a logical AND. So I changed it to this to a boolean OR, like so:

"scripts": {
    testRun "node ./runtest.js || node ./runreports.js",

Now I had the opposite problem: runreports.js only ran if runtest.js did crash!

The way to force runreports.js to always run is to ensure that the preceding condition always results in a boolean true. In boolean logic something OR true always results in true, i.e:

true || true = true
true || false = true
false || true = true

Applying that logic to my package.json script:

"scripts": {
    "(node ./runtest.js || true) && node ./runreports.js",

By wrapping he first script call with in some brackets and the ORing it with a true, the result of that bracketed section must always be true, no matter what the runtest.js script does. So runreports.js will always run.

It works for me on Windows anyway.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.