- CLI
- 开发工具
【免费下载链接】concurrently
Run commands concurrently. Like `npm run watch-js & npm run watch-less` but better.
本篇技术指南聚焦 concurrently 的 CLI 配置机制:如何通过以CONCURRENTLY_为前缀的环境变量,把--kill-others、--handle-input等常用参数变成"默认开启"的持久化配置,从而让每次执行concurrently命令时无需重复输入冗长参数。读完本文,你将掌握环境变量与 CLI 参数的完整映射规则、所有可配置参数的类型与默认值、以及参数优先级与实战组合用法。
为什么需要"配置"功能
concurrently(仓库根 README)是一个跨平台的多命令并行执行工具,CLI 形态下每次调用都需要显式传入参数,例如:
concurrently --kill-others --handle-input 'nodemon' 'echo hello'问题在于:如果某个项目总是需要--kill-others或--handle-input,那么每次执行都要重复输入这些参数,容易遗漏,也难以统一团队的使用习惯。官方文档 docs/cli/configuration.md 给出的答案是:把常用参数写入环境变量,作为"默认配置"常驻生效。
该机制的核心思路是:
- 当你想让 concurrently 总是带某些开关时,不必修改命令本身;
- 任何 concurrently 的 CLI 参数,都可以通过一个以
CONCURRENTLY_为前缀的同名环境变量来设定; - 环境变量与命令行参数是等价的,最终都会被同一个参数解析器读取。
机制解析:CONCURRENTLY_前缀是如何生效的
concurrently 的 CLI 入口是 bin/index.ts,其参数解析基于 yargs。在构建解析器时,源码中有一行关键配置:
// bin/index.ts const program = yargs(hideBin(process.argv)) .parserConfiguration({ ... }) .help('h') // ... .env('CONCURRENTLY') // ← 环境变量注入点 .options({ /* 全部 CLI 参数定义 */ });.env('CONCURRENTLY')表示:yargs 会扫描所有以CONCURRENTLY_开头的环境变量,将其去除前缀、转为 camelCase后与.options({...})中定义的参数名(如kill-others、handle-input、max-processes)进行匹配,并把匹配到的值当作该参数被显式指定。
因此,官方文档 docs/cli/configuration.md 中的示例:
$ export CONCURRENTLY_KILL_OTHERS=true $ export CONCURRENTLY_HANDLE_INPUT=true # Equivalent to passing --kill-others and --handle-input $ concurrently nodemon "echo 'hey nodemon, you won't last long'"其效果就等同于执行:
$ concurrently --kill-others --handle-input nodemon "echo 'hey nodemon, you won't last long'"也就是说,环境变量配置与命令行参数走的是同一条解析管线,最终都会汇聚到 bin/index.ts 中concurrently(...)的选项对象里。例如CONCURRENTLY_KILL_OTHERS=true最终会被转换为killOthersOn: ['success', 'failure']传入核心函数(见 bin/index.ts 中args.killOthers ? ['success', 'failure'] : ...的分支逻辑)。
提示:由于
conc是 concurrently 的别名(见 README.md),环境变量配置对conc命令同样生效,二者共享同一套解析逻辑。
可配置参数全览:环境变量名、类型与默认值
既然"任何 concurrently 的 flag 都可以用环境变量设置",那么完整参数清单就是配置的参照系。concurrently 的全部 CLI 参数定义于 bin/index.ts 的.options({...})中,默认值统一维护在 lib/defaults.ts。下表按功能分组整理:
环境变量(CONCURRENTLY_+ 下表名称) | 等价 CLI 参数 | 类型 | 默认值 | 说明 |
|---|---|---|---|---|
MAX_PROCESSES | --max-processes/-m | string(数字或 "50%" 这类百分比) | 0(全部并行) | 同时运行的进程数上限;百分比按 CPU 核数折算,见 lib/concurrently.ts 中的计算逻辑 |
NAMES | --names/-n | string(逗号分隔) | 空 | 为各进程指定自定义名字,用于前缀模板 |
SUCCESS | --success/-s | string | all | 成功条件:first/last/all/command-{name|index}等 |
RAW | --raw/-r | boolean | false | 只输出原始输出,关闭前缀美化与着色 |
NO_COLOR | --no-color | boolean | false | 关闭日志着色(Chalk 自身也会读取该值) |
HIDE | --hide | string(逗号分隔) | '' | 隐藏指定进程(按名字或索引)的输出 |
GROUP | --group/-g | boolean | false | 让输出按"顺序执行"的方式分组呈现 |
TIMINGS | --timings | boolean | false | 显示各进程的运行耗时信息 |
SHELL | --shell | string | 平台默认(Windows 为cmd.exe,其余为/bin/sh,且优先npm_config_script_shell) | 指定执行命令所用的 shell |
PASSTHROUGH_ARGUMENTS | --passthrough-arguments/-P | boolean | false | 把附加参数透传给命令(配合占位符使用) |
TEARDOWN | --teardown | string(可多次) | 无 | 退出前执行的清理命令,不影响退出码 |
KILL_OTHERS | --kill-others/-k | boolean | false | 任一进程退出后杀掉其余进程(等价于killOthersOn: ['success','failure']) |
KILL_OTHERS_ON_FAIL | --kill-others-on-fail | boolean | false | 仅当某进程以非零码退出时杀掉其余进程 |
KILL_SIGNAL | --kill-signal/-ks | string | 平台默认(Linux/macOS 为SIGTERM) | 杀进程时发送的信号,如SIGTERM/SIGKILL |
KILL_TIMEOUT | --kill-timeout | number | 无 | 强制终止进程前的等待毫秒数 |
PREFIX | --prefix/-p | string | index(设了--names则为 name) | 前缀格式:index/pid/time/command/name/none或模板 |
PREFIX_COLORS | --prefix-colors/-c | string(逗号分隔) | auto | 前缀颜色,支持 Chalk 颜色、#RRGGBB、auto等 |
PREFIX_LENGTH | --prefix-length/-l | number | 10 | 前缀展示的最大字符数(配合command前缀使用) |
PAD_PREFIX | --pad-prefix | boolean | false | 用空格补齐前缀,使所有前缀等宽 |
TIMESTAMP_FORMAT | --timestamp-format/-t | string | yyyy-MM-dd HH:mm:ss.SSS | 时间戳的 Unicode 日期格式 |
RESTART_TRIES | --restart-tries | number | 0 | 进程失败后的重启次数,负数表示无限重启 |
RESTART_AFTER | --restart-after | string(毫秒数或exponential) | 0 | 重启前的等待时间(毫秒),或exponential指数退避 |
HANDLE_INPUT | --handle-input/-i | boolean | false | 将 stdin 输入转发给子进程 |
DEFAULT_INPUT_TARGET | --default-input-target | string / number | 0 | 未指定前缀时,stdin 输入默认发送给哪个进程(索引或名字) |
以上默认值均可在 lib/defaults.ts 中找到对应定义;参数的类型与描述则以 bin/index.ts 为准。这份清单同时暗示了命名规律:环境变量名 = CLI 参数的 camelCase 形式并大写化,例如restart-tries→RESTART_TRIES、prefix-colors→PREFIX_COLORS。
值类型与书写格式
由于环境变量本身都是字符串,yargs 会根据参数定义中的type做解析:
- 布尔型参数(如
KILL_OTHERS、HANDLE_INPUT、RAW、GROUP、TIMINGS、PAD_PREFIX、PASSTHROUGH_ARGUMENTS):显式写true/false。想"默认关闭"一个本来被脚本开启的开关,也可以反向用CONCURRENTLY_XXX=false覆盖; - 数字型参数(如
RESTART_TRIES、KILL_TIMEOUT、PREFIX_LENGTH):直接写数值,如CONCURRENTLY_RESTART_TRIES=2、CONCURRENTLY_KILL_TIMEOUT=5000; - 字符串型参数(如
PREFIX、SHELL、TIMESTAMP_FORMAT、SUCCESS):直接写字符串值,如CONCURRENTLY_PREFIX=name; - 逗号分隔列表(如
NAMES、HIDE、PREFIX_COLORS):沿用 CLI 的逗号语法,如CONCURRENTLY_NAMES=main,browser,server; - 特殊取值:
MAX_PROCESSES支持"50%"这种百分比形式,核心函数 lib/concurrently.ts 会按os.cpus().length折算实际并发数;RESTART_AFTER支持exponential字符串(bin/index.ts 中专门做了判断)。
优先级与生效范围
参数来源一共有三层,其优先级遵循 yargs 的解析规则:
- 命令行显式参数(如
--kill-others)优先级最高; CONCURRENTLY_环境变量其次;- 内置默认值(lib/defaults.ts)最低。
也就是说:环境变量提供的是"默认配置"——当某条命令没有显式传参时,环境变量决定取值;一旦命令显式传入,则覆盖环境变量。这一优先级设计保证了:
- 团队可以在
.env、CI 配置或 shell profile 中统一"默认开启"某些行为; - 单次执行仍可通过显式参数临时覆盖,例如
concurrently --handle-input覆盖CONCURRENTLY_HANDLE_INPUT=false。
环境变量的生效范围是进程级的:export后对当前 shell 会话内所有concurrently/conc调用生效;若在package.json的scripts中运行,则会随 npm 脚本的执行环境一并传递。这与 docs/shell-resolution.md 中描述的 shell 解析规则属于同一类"进程环境决定行为"的设计。
实战示例
示例一:让"失败即停"成为默认行为
# ~/.bashrc 或项目 .env 中持久化 export CONCURRENTLY_KILL_OTHERS=true # 之后每次执行都自动带上 --kill-others concurrently 'npm run watch:js' 'npm run watch:css'当任一 watch 进程退出时,其余进程会被一并终止,避免"坏进程还在后台空转"。
示例二:默认开启 stdin 转发
export CONCURRENTLY_HANDLE_INPUT=true export CONCURRENTLY_DEFAULT_INPUT_TARGET=0 concurrently nodemon "echo 'hey nodemon, you won't last long'"这是官方文档 docs/cli/configuration.md 原始示例的扩展:HANDLE_INPUT让终端输入转发给子进程,DEFAULT_INPUT_TARGET指定默认接收方(索引 0 即第一个进程)。更完整的输入处理说明见 docs/cli/input-handling.md。
示例三:组合多个配置项
export CONCURRENTLY_MAX_PROCESSES=2 export CONCURRENTLY_PREFIX=name export CONCURRENTLY_PREFIX_COLORS=auto export CONCURRENTLY_RESTART_TRIES=3 export CONCURRENTLY_RESTART_AFTER=1000 concurrently 'tsc -w' 'jest --watch' 'eslint --watch'这条命令等效于:
concurrently \ --max-processes 2 \ --prefix name \ --prefix-colors auto \ --restart-tries 3 \ --restart-after 1000 \ 'tsc -w' 'jest --watch' 'eslint --watch'关于前缀样式(PREFIX、PREFIX_COLORS、PREFIX_LENGTH、TIMESTAMP_FORMAT)的完整语义,可参考 docs/cli/prefixing.md;重启行为(RESTART_TRIES、RESTART_AFTER)详见 docs/cli/restarting.md;输出控制(RAW、GROUP、HIDE、TIMINGS)详见 docs/cli/output-control.md。
示例四:临时覆盖环境变量
# 环境变量默认开启了 kill-others,但这次想保留所有进程 concurrently --no-kill-others ... # 不存在这样的 flag,正确做法是:注意:布尔开关类参数没有反义 flag,覆盖方式是在命令显式传参或用
false重新赋值环境变量,例如CONCURRENTLY_KILL_OTHERS=false concurrently ...。这也再次印证了"环境变量提供默认值、显式参数与环境变量共同决定最终取值"的模型。
与编程式 API 的对应关系
环境变量配置只作用于CLI 形态;如果你在代码中直接调用 API,则需把同样的选项写进concurrently(commands, options)的第二个参数。CLI 参数与 API 选项一一对应,例如kill-others对应killOthersOn、handle-input对应handleInput、max-processes对应maxProcesses,完整的选项定义见 lib/index.ts 中的ConcurrentlyOptions类型。也就是说,"默认配置"这件事在编程场景下等价于"把公共选项提取到一个共享的 options 对象里"——CLI 的环境变量方案本质上是为命令行使用场景提供了同样的"一次配置、处处生效"能力。
小结
CONCURRENTLY_前缀环境变量是 concurrently 面向 CLI 的"配置文件":借助 bin/index.ts 中的.env('CONCURRENTLY'),所有 CLI 参数都可以被环境变量预设为默认值,并遵循"显式参数 > 环境变量 > 内置默认值"的优先级。把这套机制与 docs/cli/configuration.md 之外的其他 CLI 文档(前缀、输出控制、成功条件、终止、重启、输入处理、透传参数、快捷键)配合使用,即可把团队的并发命令执行习惯沉淀为可持续、可复现的默认配置。
- CLI
- 开发工具
【免费下载链接】concurrently
Run commands concurrently. Like `npm run watch-js & npm run watch-less` but better.
相关推荐
FerretDB 配置旗标完全指南:命令行参数、环境变量与源码级默认值解析
FerretDB 配置旗标完全指南:命令行参数、环境变量与源码级默认值解析 FerretDB 提供了一套完整的配置旗标(configuration flags)
后端数据库文档数据库Intero项目终结启示录:为什么这个Haskell开发利器停止维护?
Intero项目终结启示录:为什么这个Haskell开发利器停止维护? Intero曾是Haskell开发者的终极IDE工具,提供实时代码补全、错误检查和定义跳
Aider CLI 全量选项参考:从命令行参数、环境变量到 YAML 配置的完整指南
Aider CLI 全量选项参考:从命令行参数、环境变量到 YAML 配置的完整指南 本文以 aider 官方文档 Options reference http
人工智能大模型AI Agent代码智能体交互助手CLI开发工具
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考