npm 运行脚本中参数的 if-else

Fra*_*cke 5 csh sh npm package.json

我想调用不同的其他脚本,具体取决于是否给出了参数:

"paramtest": "if [ -z $1 ]; then echo Foo $1; else echo Bar; fi",
Run Code Online (Sandbox Code Playgroud)

npm 运行参数测试

应该给“酒吧”。

npm run paramtest -- 随便

应该给“Foo what”。

但是在实践中我只得到:(参数被添加到整行,而不是“传入”)

> if [ -z $1 ]; then echo Foo; else echo Bar; fi "whatever
  sh: 1: Syntax error: word unexpected
Run Code Online (Sandbox Code Playgroud)

我可以做什么更好?

基本上我是在运行完整的测试套件/只使用相同的命令进行单独测试之后......

"test" : "if [ -z $1 ]; then mocha ./test/**/*.test.js; else mocha $1
Run Code Online (Sandbox Code Playgroud)

Jos*_*bst 4

将其包装在 shell 函数中应该可以解决问题:

"test": "f() { if [ $# -eq 0 ]; then mocha './test/**/*.test.js'; else mocha -- \"$@\"; fi; }; f"
Run Code Online (Sandbox Code Playgroud)

请注意,我稍微更改了 if 条件和 else 分支,以便您可以在必要时指定多个文件参数。

更简洁的方法:

"test": "f() { mocha -- \"${@:-./test/**/*.test.js}\"; }; f"
Run Code Online (Sandbox Code Playgroud)

以这种方式使用 shell 函数可能看起来很熟悉,因为同样的技术也经常用于git aliases


详细说明

我们用这个脚本来演示一下:

"scripts": {
    "myscript": "if [ \"$1\" = one ]; then printf %s\\\\n \"$@\"; else echo false; fi"
}
Run Code Online (Sandbox Code Playgroud)

这里如果第一个参数是“one”,我们打印所有参数,否则我们打印“false”。我们当然假设npm run-script使用的是类似 sh 的 shell,而不是 Windows 的 cmd.exe。

我在npm 文档中看不到任何具体详细说明如何将参数传递给脚本的内容,因此让我们看一下源代码(撰写本文时为 npm v6.14.7)。看起来脚本是在这里与它的参数连接起来,然后 在这里执行的。本质上,npm run myscript -- one two three变成

sh -c 'if [ "$1" = one ]; then printf %s\\n "$@"; else echo false; fi "one" "two" "three"'
Run Code Online (Sandbox Code Playgroud)

我们的参数one two three只是用引号转义并连接到脚本命令。就 shell 语法而言,这意味着它们最终将作为fi. sh当然拒绝这一点,因为fi它只是一个内置的结束if并且不带任何参数。

我们的目标更像是

sh -c 'if [ "$1" = one ]; then printf %s\\n "$@"; else echo false; fi' sh "one" "two" "three"
Run Code Online (Sandbox Code Playgroud)

这里onetwo、 和是 sh 本身的参数,因此成为给定脚本中的three参数变量$1$2、 和。$3npm 不允许我们直接执行此操作,但我们可以通过将脚本包装在 shell 函数中来完成相同的操作:

"scripts": {
    "myscript": "f() { if [ \"$1\" = one ]; then printf %s\\\\n \"$@\"; else echo false; fi; }; f"
}
Run Code Online (Sandbox Code Playgroud)

这里的脚本以函数的调用结束,因此 npm 最终将连接此调用的参数,最终将函数调用为f "one" "two" "three"

sh -c 'f() { if [ "$1" = one ]; then printf %s\\n "$@"; else echo false; fi; }; f "one" "two" "three"'
Run Code Online (Sandbox Code Playgroud)