将命令行参数发送到npm脚本


816

scriptspackage.json当前的部分看起来像这样:

"scripts": {
    "start": "node ./script.js server"
}

...这意味着我可以运行npm start来启动服务器。到目前为止,一切都很好。

但是,我希望能够运行类似的东西npm start 8080并将参数传递给script.js(例如npm start 8080=> node ./script.js server 8080)。这可能吗?

Answers:


1128

编辑2014.10.30: 可以将args传递给npm runnpm 2.0.0

语法如下:

npm run <command> [-- <args>]

注意必要的--。需要将传递给npm命令本身的参数和传递给脚本的参数分开。

所以如果你有 package.json

"scripts": {
    "grunt": "grunt",
    "server": "node server.js"
}

那么以下命令将是等效的:

grunt task:target => npm run grunt -- task:target

node server.js --port=1337 => npm run server -- --port=1337

要获取参数值,请参阅此问题。为了读取命名参数,最好使用yargsminimist之类的解析库;nodejs process.argv在全局范围内公开,其中包含命令行参数值,但这是一个低级API(空格分隔的字符串数组,由操作系统提供给节点可执行文件)。


编辑2013.10.03:目前无法直接进行。但是还有一个相关的GitHub问题npm即将开放,以实现您要求的行为。似乎已经实现了共识,但这取决于之前要解决的另一个问题。


原始答案:作为一种变通办法(尽管不是很方便),您可以执行以下操作:

从说你包的名字package.json就是myPackage你必须还

"scripts": {
    "start": "node ./script.js server"
}

然后添加package.json

"config": {
    "myPort": "8080"
}

并在您的script.js

// defaulting to 8080 in case if script invoked not via "npm run-script" but directly
var port = process.env.npm_package_config_myPort || 8080

这样,默认情况下npm start将使用8080。但是,您可以对其进行配置(该值将存储npm在其内部存储器中):

npm config set myPackage:myPort 9090

然后,在调用时npm start,将使用9090(来自的默认值package.json将被覆盖)。


1
这也可以与像这样的软件包完美地结合在一起yargs; 之后的所有参数--都可以在脚本中完美解析。
汤玛斯(Thomas)

11
AFAIKS,这只能将参数添加到脚本的末尾..如果中间需要参数怎么办?
Spock

108
-- --args哇靠这是奇怪,但没关系
八月

9
@Spock可以使用shell函数。这是一个eslint + tslint设置,我用于允许通过“ npm run lint--f unix”将自定义args传递给eslint: tslint && echo'lint clean!';}; f“
ecmanaut

3
设置“ myPackage:myPort 9090”值的更好方法是使用命令“ --myPackage:myPort = 9090”的配置标志-keithcirkel.co.uk/how-to-use-npm-as-a-build工具
chrismarx

221

您要求能够运行类似 npm start 8080。这是可能的,而无需script.js按如下所述修改或配置文件。

例如,在您的"scripts"JSON值中,包括-

"start": "node ./script.js server $PORT"

然后从命令行:

$ PORT=8080 npm start

我已经确认使用bash和npm 1.4.23可以正常工作。请注意,此替代方法不需要解决GitHub npm 问题#3494


19
这真的很好。您也可以做一些node ./script.js server ${PORT:-8080}使其可选的操作。
graup

7
我似乎无法使用git bash在Windows中执行此操作。有人可以吗?(对ubuntu使用相同的命令)
KarolisŠarapnickis16年

3
嘿@graup这对我NODE_PORT=${PORT=8080}有用(注意相等),但不是:-语法
MaieonBrix

14
这在跨平台上不起作用!例如,在Windows上,该命令必须为node ./script.js server %PORT%。考虑使用cross-varcross-env
Stijn de Witt

使用env vars作为cli args的用例似乎仅限于我?也可以使用config模块之类的东西来处理env var,默认值和常规配置。
Mr5o1

93

您也可以这样做:

package.json

"scripts": {
    "cool": "./cool.js"
}

cool.js

 console.log({ myVar: process.env.npm_config_myVar });

在CLI中:

npm --myVar=something run-script cool

应该输出:

{ myVar: 'something' }

更新:使用npm 3.10.3,它似乎将process.env.npm_config_变量小写了吗?我还使用better-npm-run,所以我不知道这是香草默认行为或没有,但这个答案正在工作。代替process.env.npm_config_myVar尝试process.env.npm_config_myvar


4
谢谢,这对我有用!我所缺少的是您在命令行中指定的变量名称的“ npm_config_”前缀。
jp093121 2015年

2
错了 process.env.npm_config_myVar返回true,而不是值。
莫里森

1
适用于npm 6.8.0版,但仅在变量名使用小写字母时有效。看起来lilke npm将其更改为小写字母
Ofir

很好的解决方案,可在npm 6.5.0上使用小写参数
-GavinBelson,

77

jakub.g的答案是正确的,但是使用grunt的示例似乎有点复杂。

所以我的答案很简单:

-将命令行参数发送到npm脚本

用于向npm脚本发送命令行参数的语法:

npm run [command] [-- <args>]

假设我们在package.json中有一个npm start任务来启动webpack开发服务器:

"scripts": {
  "start": "webpack-dev-server --port 5000"
},

我们从命令行运行 npm start

现在,如果我们想将端口传递给npm脚本:

"scripts": {
  "start": "webpack-dev-server --port process.env.port || 8080"
},

运行此命令并通过命令行传递端口(例如5000),如下所示:

npm start --port:5000

-使用package.json配置:

jakub.g所述,您也可以在package.json的配置中设置参数

"config": {
  "myPort": "5000"
}

"scripts": {
  "start": "webpack-dev-server --port process.env.npm_package_config_myPort || 8080"
},

npm start 将使用配置中指定的端口,或者您可以覆盖它

npm config set myPackage:myPort 3000

-在npm脚本中设置参数

读取npm脚本中的变量集的示例。在这个例子中NODE_ENV

"scripts": {
  "start:prod": "NODE_ENV=prod node server.js",
  "start:dev": "NODE_ENV=dev node server.js"
},

在阅读NODE_ENV server.js无论是督促开发

var env = process.env.NODE_ENV || 'prod'

if(env === 'dev'){
    var app = require("./serverDev.js");
} else {
    var app = require("./serverProd.js");
}

5
请注意,除非您使用cross-env,否则"start:prod": "NODE_ENV=prod node server.js"in 中的语法package.json将无法在Windows上使用
jakub.g

2
更正?: "start": "webpack-dev-server --port process.env.npm_package_config_myPort || 8080" },应该"start": "webpack-dev-server --port $npm_package_config_myPort || 8080" },根据本教程说明的用途使用。显然,可以在javascript中使用process ref。
亚伦·罗勒


34

process.argv在您的代码中使用,然后仅提供$*到脚本值条目的尾随即可。

例如,使用简单的脚本尝试一下,该脚本仅将提供的参数记录到standard out中echoargs.js

console.log('arguments: ' + process.argv.slice(2));

package.json:

"scripts": {
    "start": "node echoargs.js $*"
}

例子:

> npm start 1 2 3
arguments: 1,2,3

process.argv[0]是可执行文件(节点),process.argv[1]是您的脚本。

已通过npm v5.3.0和节点v8.4.0测试


添加后不能正常工作--,以参数,例如: - npm run demo.js --skip,它的工作原理,如果增加了额外的--,例如: -npm run demo.js -- --skip
Shreyas

您可以在没有单独的echoargs.js脚本文件的情况下使用此方法吗?
约书亚·品特

@JoshuaPinter echoargs.js仅作为示例,我将编辑我的答案以使之变得清晰
彼得

@Peter对,但是它必须是脚本文件。我正在尝试创建一个脚本,该脚本adb用于将.db文件推送到Android模拟器并接受将.db文件的本地路径推送到它的参数,这是的第一个参数adb push。这样的事情:"db:push": "adb push process.argv.slice(2) /data/data/com.cntral.app/databases/database.db"我想用来称呼它npm run db:push /Users/joshuapinter/Downloads/updated.db。有什么想法吗?
约书亚·品特

21

如果要将参数传递给npm脚本的中间,而不是将参数附加到末尾,则内联环境变量似乎可以很好地工作:

"scripts": {
  "dev": "BABEL_ARGS=-w npm run build && cd lib/server && nodemon index.js",
  "start": "npm run build && node lib/server/index.js",
  "build": "mkdir -p lib && babel $BABEL_ARGS -s inline --stage 0 src -d lib",
},

在这里,npm run dev-w监视标志传递给babel,但npm run start只运行一次常规构建。


从CLI如何称呼它?
bwobst

@dresdin npm run devnpm start
TJ

2
需要使用cross-env才能在Windows上使用它。
fracz

7

我过去一直使用这种单行代码,并且在离开Node.js一段时间后不得不最近尝试重新发现它。与@francoisrv提到的解决方案类似,它利用node_config_*变量。

创建以下最小package.json文件:

{
  "name": "argument",
  "version": "1.0.0",
  "scripts": {
    "argument": "echo \"The value of --foo is '${npm_config_foo}'\""
  }
}

运行以下命令:

npm run argument --foo=bar

观察以下输出:

--foo的值是'bar'

所有这些都很好地记录在npm官方文档中:

注意:环境变量”标题说明脚本中的变量的行为与文档中定义的行为不同。在区分大小写以及参数是用空格还是等号定义时,都是如此

注意:如果您使用带连字符的参数,则会在相应的环境变量中将其替换为下划线。例如,npm run example --foo-bar=baz将对应于${npm_config_foo_bar}

注意:对于非WSL Windows用户,请参阅下面的@Doctor Blue的注释... TL; DR替换${npm_config_foo}%npm_config_foo%


你好。我正在尝试使用您的示例,但恐怕它对我不起作用。我复制粘贴了您的“参数”脚本,并为运行命令(npm run argument --foo=bar)做了相同的操作,但是未替换该变量:"The value of --foo is '${npm_config_foo}'"。如果重要的话,请在Windows 10上运行NPM 6.9.0版。
Blue

@DoctorBlue稀释权,节点和Windows并不总是发挥不错...这篇文章可能会在NPM脚本一些线索环境变量:(TL; DR命令直接进入主机操作系统,即使从另一个shell启动)博客.risingstack.com / node-js-windows-10-tutorial /…我不确定您的设置,但是如果您使用Git Bash运行Node,则可能要考虑通过WSL :) 文档
Andrew Odri

1
我想到了。只是不得不使用%npm_config_foo%代替。纯Windows命令行/ Powershell在这里。(也别无选择。)
蓝医生

6

这并不能真正回答您的问题,但是您始终可以使用环境变量:

"scripts": {
    "start": "PORT=3000 node server.js"
}

然后在您的server.js文件中:

var port = process.env.PORT || 3000;

1
只要您在Unix平台上,这就很好。不幸的是,它不能用于Windows,因为它具有自己的约定。
JuhoVepsäläinen15年

6

上面的大多数答案仅涉及将参数传递到由npm调用的NodeJS脚本中。我的解决方案是通用的。

只需使用shell解释程序(例如sh)调用包装npm脚本,然后照常传递参数即可。唯一的例外是第一个参数编号为0

例如,您要添加npm脚本someprogram --env=<argument_1>,其中someprogram仅打印env参数的值:

package.json

"scripts": {
  "command": "sh -c 'someprogram --env=$0'"
}

运行时:

% npm run -s command my-environment
my-environment

谢谢!这太完美了!
Felipe Desiderati

简洁大方!在MS DOS外壳上将无法使用。
n370

3

从我的角度来看,人们希望以更简单的方式运行脚本时会使用package.json脚本。例如,要使用nodemon安装在本地node_modules中的插件,我们不能nodemon直接从cli调用,但是可以使用调用它./node_modules/nodemon/nodemon.js。因此,为了简化这种长类型输入,我们可以将其...

    ...

    脚本:{
      '开始':'nodemon app.js'
    }

    ...

...然后调用npm start以使用以app.js作为第一个参数的'nodemon'。

我想说的是,如果您只想使用该node命令启动服务器,那么我认为您无需使用scripts。打字npm startnode app.js具有相同的努力。

但是,如果您确实想使用nodemon,并且想要传递动态参数,则不要使用script任何一个。尝试改用symlink。

例如,使用进行迁移sequelize。我创建一个符号链接...

ln -s node_modules/sequelize/bin/sequelize sequelize

...当我称呼它时,我可以通过任何争论...

./sequlize -h /* show help */

./sequelize -m /* upgrade migration */

./sequelize -m -u /* downgrade migration */

等等...

在这一点上,使用symlink是我能弄清楚的最佳方法,但我并不认为这是最佳实践。

我也希望您的意见对我的回答。


1
这根本无法回答问题。我不知道它是如何获得6次投票的,但是恭喜:)
Dan Dascalescu

2

注意:这种方法可以package.json即时修改,如果没有其他选择,请使用它。

我必须将命令行参数传递给脚本,如下所示:

"scripts": {
    "start": "npm run build && npm run watch",
    "watch": "concurrently  \"npm run watch-ts\" \"npm run watch-node\"",
    ...
}

因此,这意味着我使用来启动我的应用npm run start

现在,如果我想传递一些参数,则可能从以下内容开始:

npm run start -- --config=someConfig

这是什么:npm run build && npm run watch -- --config=someConfig。问题在于,它总是将参数附加到脚本的末尾。这意味着所有链接的脚本都不会获得这些参数(所有人可能都需要Args,也可能不需要,但这是另一回事了。)。此外,当调用链接的脚本时,这些脚本将不会获得传递的参数。即watch脚本将无法获取传递的参数。

我的应用程序的生产用途是作为.exe,因此在exe中传递参数可以正常工作,但是如果要在开发过程中这样做,就很麻烦。

我找不到任何合适的方法来实现这一目标,所以这就是我所尝试的。

我创建了一个javascript文件:start-script.js在应用程序的父级上,我有一个“ default.package.json”,而没有维护“ package.json”,而是维护了“ default.package.json”。的目的start-script.json是读取default.package.json,提取scripts和查找,npm run scriptname然后将传递的参数附加到这些脚本。之后,它将创建一个新文件,package.json并使用修改后的脚本从default.package.json复制数据,然后调用npm run start

const fs = require('fs');
const { spawn } = require('child_process');

// open default.package.json
const defaultPackage = fs.readFileSync('./default.package.json');
try {
    const packageOb = JSON.parse(defaultPackage);
    // loop over the scripts present in this object, edit them with flags
    if ('scripts' in packageOb && process.argv.length > 2) {

        const passedFlags = ` -- ${process.argv.slice(2).join(' ')}`;
        // assuming the script names have words, : or -, modify the regex if required.
        const regexPattern = /(npm run [\w:-]*)/g;
        const scriptsWithFlags = Object.entries(packageOb.scripts).reduce((acc, [key, value]) => {
            const patternMatches = value.match(regexPattern);
            // loop over all the matched strings and attach the desired flags.
            if (patternMatches) {
                for (let eachMatchedPattern of patternMatches) {
                    const startIndex = value.indexOf(eachMatchedPattern);
                    const endIndex = startIndex + eachMatchedPattern.length;
                    // save the string which doen't fall in this matched pattern range.
                    value = value.slice(0, startIndex) + eachMatchedPattern + passedFlags + value.slice(endIndex);
                }
            }
            acc[key] = value;
            return acc;
        }, {});
        packageOb.scripts = scriptsWithFlags;
    }

    const modifiedJSON = JSON.stringify(packageOb, null, 4);
    fs.writeFileSync('./package.json', modifiedJSON);

    // now run your npm start script
    let cmd = 'npm';
    // check if this works in your OS
    if (process.platform === 'win32') {
        cmd = 'npm.cmd';    // https://github.com/nodejs/node/issues/3675
    }
    spawn(cmd, ['run', 'start'], { stdio: 'inherit' });

} catch(e) {
    console.log('Error while parsing default.package.json', e);
}

现在npm run start,我没有做,而是node start-script.js --c=somethis --r=somethingElse

最初的运行看起来不错,但尚未进行全面测试。如果您喜欢自己的应用程序开发,请使用它。


1

我在尝试运行sequelize seed:generate cli命令来解决我的问题时发现了这个问题:

node_modules/.bin/sequelize seed:generate --name=user

让我说清楚。我想在我的package.json文件中有一个简短的脚本命令,并同时提供--name参数

答案是经过一些实验后得出的。这是我在package.json中的命令

"scripts: {
  "seed:generate":"NODE_ENV=development node_modules/.bin/sequelize seed:generate"
}

...这是在终端中运行它以为用户生成种子文件的示例

> yarn seed:generate --name=user

> npm run seed:generate -- --name=user

费耶

yarn -v
1.6.0

npm -v
5.6.0

2
这项技术与2013年接受的答案中说明的技术相同-- --arg1, ...吗?
Dan Dascalescu

2
好,那为什么要重复答案呢?
Dan Dascalescu

我分享了一个独特的用法示例,这不是很明显吗?
Serge Seletskyy,

2
如果我想分享另一示例中已经在其他答案中说明的技术,则可以将我的示例作为对该答案的注释。
Dan Dascalescu

1
陷阱

0

npm run script_target-<参数>基本上这是传递命令行参数的方式,但仅当脚本仅运行一个命令(例如我正在运行命令)时,它才有效,即npm run start-4200

"script":{
       "start" : "ng serve --port="
 }

这将为传递命令行参数而运行,但是如果我们一起运行多个命令,如npm,运行build c:/ workspace / file会怎样?

"script":{
       "build" : "copy c:/file <arg> && ng build"
 } 

但是在运行副本c:/ file && ng build c:/ work space / file时它将像这样的解释器, 并且我们期望这样的 副本c:/ file c:/ work space / file && ng build

注意:--因此,命令行参数仅在脚本中只有一个命令的情况下才能正常工作。

我在上面阅读了一些答案,其中有一些正在写中,您可以使用$符号访问命令行参数,但这将无法工作


0

我知道已经有一个批准的答案,但是我有点喜欢这种JSON方法。

npm start '{"PROJECT_NAME_STR":"my amazing stuff", "CRAZY_ARR":[0,7,"hungry"], "MAGICAL_NUMBER_INT": 42, "THING_BOO":true}';

通常,我有1个需要的变量,例如项目名称,所以我觉得这很简单。

我的package.json中也经常有这样的东西

"scripts": {
    "start": "NODE_ENV=development node local.js"
}

贪婪的我想要“全部”,NODE_ENV CMD行arg的东西。

您只需在文件中访问这些内容(对于我来说就是local.js)

console.log(process.env.NODE_ENV, starter_obj.CRAZY_ARR, starter_obj.PROJECT_NAME_STR, starter_obj.MAGICAL_NUMBER_INT, starter_obj.THING_BOO);

您只需要在它上面放一点(我正在运行v10.16.0 btw)

var starter_obj = JSON.parse(JSON.parse(process.env.npm_config_argv).remain[0]);

Anyhoo,问题已经回答。以为我会分享,因为我经常使用这种方法。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.