Node.js: os 与 process 模块
最后更新:2026-08-26
Alice 是一名 DevOps 工程师,负责管理数十台服务器。每次部署新应用时,她都要手动登录服务器检查 CPU 核心数、可用内存、操作系统版本,再根据环境变量切换配置。一天凌晨 3 点的紧急部署中,她因手动检查遗漏了内存不足的问题导致部署失败。于是她决定用 Node.js 写一个自动检测脚本,一键获取服务器资源和环境信息,让部署不再踩坑。
1. 你将学到
- os 模块核心方法:获取 CPU、内存、主机名、平台等信息
- process 模块核心属性:argv、env、exit、cwd 等
- 标准流操作:stdin / stdout / stderr
- process.nextTick() 的执行时机与用途
- 环境变量管理:.env 文件与 dotenv 库
- 构建跨平台 CLI 工具的实践技巧
2. os 模块:系统信息采集
(1) CPU 与内存信息
os.cpus() 返回 CPU 核心详细信息数组,os.totalmem() 和 os.freemem() 分别返回总内存和可用内存(单位:字节)。
▶ 示例:检测服务器 CPU 与内存
const os = require('os');
const cpus = os.cpus();
console.log(`CPU 核心数: ${cpus.length}`);
console.log(`CPU 型号: ${cpus[0].model}`);
const totalMem = os.totalmem();
const freeMem = os.freemem();
const usedPercent = ((totalMem - freeMem) / totalMem * 100).toFixed(1);
console.log(`总内存: ${(totalMem / 1024 / 1024 / 1024).toFixed(2)} GB`);
console.log(`可用内存: ${(freeMem / 1024 / 1024 / 1024).toFixed(2)} GB`);
console.log(`内存使用率: ${usedPercent}%`);
CPU 核心数: 8
CPU 型号: Intel(R) Core(TM) i7-9700K CPU @ 3.60GHz
总内存: 15.88 GB
可用内存: 6.23 GB
内存使用率: 60.7%
(2) 操作系统标识
os.platform() 返回平台标识(如 win32、linux、darwin),os.type() 返回操作系统名称,os.arch() 返回 CPU 架构,os.hostname() 返回主机名。
▶ 示例:获取操作系统信息
const os = require('os');
console.log(`平台: ${os.platform()}`);
console.log(`系统类型: ${os.type()}`);
console.log(`CPU 架构: ${os.arch()}`);
console.log(`主机名: ${os.hostname()}`);
console.log(`系统版本: ${os.version()}`);
平台: linux
系统类型: Linux
CPU 架构: x64
主机名: web-server-01
系统版本: #1 SMP Thu Jan 1 00:00:00 UTC 2026
(3) 用户与目录信息
os.userInfo() 返回当前用户信息,os.homedir() 返回用户主目录,os.tmpdir() 返回临时文件目录。
▶ 示例:获取用户与目录信息
const os = require('os');
const userInfo = os.userInfo();
console.log(`用户名: ${userInfo.username}`);
console.log(`主目录: ${os.homedir()}`);
console.log(`Shell: ${userInfo.shell}`);
console.log(`临时目录: ${os.tmpdir()}`);
用户名: alice
主目录: /home/alice
Shell: /bin/bash
临时目录: /tmp
(4) 网络接口信息
os.networkInterfaces() 返回所有网络接口的详细信息,包括 IP 地址、MAC 地址和地址族。
▶ 示例:查看网络接口
const os = require('os');
const interfaces = os.networkInterfaces();
for (const [name, addrs] of Object.entries(interfaces)) {
for (const addr of addrs) {
if (addr.family === 'IPv4' && !addr.internal) {
console.log(`${name}: ${addr.address} (${addr.family})`);
}
}
}
eth0: 192.168.1.100 (IPv4)
wlan0: 10.0.0.5 (IPv4)
(5) os 常用方法速查
| 方法 | 返回值类型 | 用途 |
|---|---|---|
os.cpus() |
object[] |
CPU 核心信息数组 |
os.totalmem() |
number |
总内存(字节) |
os.freemem() |
number |
可用内存(字节) |
os.platform() |
string |
平台标识(win32/linux/darwin) |
os.type() |
string |
操作系统名称 |
os.arch() |
string |
CPU 架构(x64/arm64) |
os.hostname() |
string |
主机名 |
os.userInfo() |
object |
当前用户信息 |
os.homedir() |
string |
用户主目录路径 |
os.tmpdir() |
string |
临时文件目录路径 |
os.networkInterfaces() |
object |
网络接口信息 |
os.uptime() |
number |
系统运行时间(秒) |
os.loadavg() |
number[] |
系统负载均值(1/5/15分钟) |
os.EOL |
string |
换行符常量 |
os.devNull |
string |
空设备路径 |
3. process 模块:进程控制
(1) 命令行参数 process.argv
process.argv 是一个数组,argv[0] 是 Node.js 可执行文件路径,argv[1] 是被执行的脚本路径,后续元素是传入的命令行参数。
flowchart TD
A["命令行输入<br/>node app.js --env prod --port 3000"] --> B["process.argv 数组"]
B --> C["argv[0]: Node.js 路径<br/>/usr/local/bin/node"]
B --> D["argv[1]: 脚本路径<br/>/home/alice/app.js"]
B --> E["argv[2]: --env"]
B --> F["argv[3]: prod"]
B --> G["argv[4]: --port"]
B --> H["argv[5]: 3000"]
E --> I["参数解析逻辑"]
G --> I
I --> J["{ env: 'prod', port: '3000' }"]
▶ 示例:解析命令行参数
function parseArgs(argv) {
const args = {};
for (let i = 2; i < argv.length; i++) {
if (argv[i].startsWith('--')) {
const key = argv[i].slice(2);
const value = argv[i + 1] && !argv[i + 1].startsWith('--')
? argv[++i]
: true;
args[key] = value;
}
}
return args;
}
const config = parseArgs(process.argv);
console.log(config);
node cli.js --env production --port 8080 --verbose
{ env: 'production', port: '8080', verbose: true }
(2) 环境变量 process.env
process.env 包含所有环境变量的键值对,是部署脚本判断运行环境的核心依据。
▶ 示例:读取与设置环境变量
console.log(`NODE_ENV: ${process.env.NODE_ENV || 'development'}`);
console.log(`PATH: ${process.env.PATH}`);
process.env.APP_MODE = 'production';
console.log(`APP_MODE: ${process.env.APP_MODE}`);
NODE_ENV: development
PATH: /usr/local/bin:/usr/bin:/bin
APP_MODE: production
(3) 进程退出与工作目录
process.exit(code) 终止进程(0 表示成功,非 0 表示失败),process.cwd() 返回当前工作目录。
▶ 示例:条件退出与目录检查
const requiredEnv = ['DATABASE_URL', 'APP_SECRET'];
const missing = requiredEnv.filter(key => !process.env[key]);
if (missing.length > 0) {
console.error(`缺少必需环境变量: ${missing.join(', ')}`);
process.exit(1);
}
console.log(`工作目录: ${process.cwd()}`);
console.log(`进程 ID: ${process.pid}`);
console.log(`运行时间: ${process.uptime().toFixed(0)} 秒`);
缺少必需环境变量: DATABASE_URL, APP_SECRET
(4) 标准流:stdin / stdout / stderr
process.stdout 和 process.stderr 是可写流,process.stdin 是可读流,用于与终端交互。
▶ 示例:使用标准流输出与输入
process.stdout.write('请输入您的名称: ');
process.stdin.once('data', (data) => {
const name = data.toString().trim();
process.stdout.write(`你好, ${name}!\n`);
process.exit(0);
});
请输入您的名称: Alice
你好, Alice!
(5) process.nextTick()
process.nextTick() 将回调放入微任务队列,在当前操作完成后、I/O 事件之前执行,常用于确保异步操作按预期顺序进行。
▶ 示例:nextTick 执行顺序
console.log('1 - 同步代码');
process.nextTick(() => {
console.log('3 - nextTick 回调');
});
console.log('2 - 同步代码');
setImmediate(() => {
console.log('5 - setImmediate');
});
Promise.resolve().then(() => {
console.log('4 - Promise then');
});
1 - 同步代码
2 - 同步代码
3 - nextTick 回调
4 - Promise then
5 - setImmediate
(6) process 常用属性/方法速查
| 属性/方法 | 类型 | 用途 |
|---|---|---|
process.argv |
string[] |
命令行参数数组 |
process.env |
object |
环境变量对象 |
process.exit(code) |
方法 | 终止进程 |
process.cwd() |
方法 | 返回当前工作目录 |
process.pid |
number |
当前进程 ID |
process.uptime() |
方法 | 进程运行时间(秒) |
process.stdin |
ReadStream |
标准输入流 |
process.stdout |
WriteStream |
标准输出流 |
process.stderr |
WriteStream |
标准错误流 |
process.nextTick(cb) |
方法 | 微任务调度 |
process.platform |
string |
运行平台 |
process.version |
string |
Node.js 版本 |
process.versions |
object |
各组件版本信息 |
process.kill(pid) |
方法 | 发送信号给进程 |
process.title |
string |
进程标题 |
4. 跨平台常量与路径处理
(1) 换行符与路径分隔符
不同操作系统的换行符和路径分隔符不同,直接硬编码会导致跨平台问题。
▶ 示例:使用 os.EOL 与 os.sep
const os = require('os');
const path = require('path');
const lines = ['第一行', '第二行', '第三行'].join(os.EOL);
console.log('换行符转义:', JSON.stringify(os.EOL));
console.log('路径分隔符:', os.sep);
console.log('path.join 结果:', path.join('src', 'utils', 'index.js'));
换行符转义: "\n"
路径分隔符: /
path.join 结果: src/utils/index.js
(2) 跨平台路径/换行符常量对比
| 常量 | Windows 值 | POSIX 值 | 用途 |
|---|---|---|---|
os.EOL |
\r\n |
\n |
换行符 |
os.sep |
\ |
/ |
路径分隔符 |
path.sep |
\ |
/ |
路径分隔符(path 模块) |
os.devNull |
nul |
/dev/null |
空设备路径 |
path.delimiter |
; |
: |
PATH 环境变量分隔符 |
5. 环境变量管理:.env 与 dotenv
(1) dotenv 库基础用法
dotenv 库从 .env 文件加载环境变量到 process.env,是管理项目配置的业界标准方案。
▶ 示例:使用 dotenv 加载 .env 文件
创建 .env 文件:
NODE_ENV=production
DATABASE_URL=postgresql://db.example.com:5432/myapp
APP_SECRET=my-super-secret-key
APP_PORT=3000
在代码中加载:
require('dotenv').config();
console.log(`环境: ${process.env.NODE_ENV}`);
console.log(`数据库: ${process.env.DATABASE_URL}`);
console.log(`端口: ${process.env.APP_PORT}`);
环境: production
数据库: postgresql://db.example.com:5432/myapp
端口: 3000
(2) 环境变量设置方式对比
| 方式 | 作用范围 | 持久性 | 适用场景 |
|---|---|---|---|
Shell 临时设置 (export KEY=val) |
当前终端会话 | 会话结束消失 | 临时调试 |
.env 文件 + dotenv |
当前 Node 进程 | 文件持久 | 项目开发 |
| 系统环境变量 | 全局用户/系统 | 永久 | 服务器部署 |
| Docker ENV / env-file | 容器内 | 容器生命周期 | 容器化部署 |
| CI/CD 平台设置 | CI/CD 流水线 | 流水线内 | 持续集成 |
(3) 安全读取环境变量
▶ 示例:带验证的环境变量读取
function getEnv(key, options = {}) {
const value = process.env[key];
if (value === undefined) {
if (options.required) {
throw new Error(`环境变量 ${key} 是必需的`);
}
return options.default ?? null;
}
if (options.type === 'number') {
const num = Number(value);
if (isNaN(num)) throw new Error(`环境变量 ${key} 必须是数字`);
return num;
}
if (options.type === 'boolean') {
return value === 'true' || value === '1';
}
return value;
}
const port = getEnv('APP_PORT', { default: 3000, type: 'number' });
const debug = getEnv('DEBUG', { default: false, type: 'boolean' });
const dbUrl = getEnv('DATABASE_URL', { required: true });
6. 综合示例:系统诊断 CLI 工具
构建一个完整的 CLI 工具:检测 OS/内存/CPU → 读取环境变量 → 格式化输出报告。
▶ 示例:syscheck.js
const os = require('os');
function parseArgs(argv) {
const args = {};
for (let i = 2; i < argv.length; i++) {
if (argv[i].startsWith('--')) {
const key = argv[i].slice(2);
const value = argv[i + 1] && !argv[i + 1].startsWith('--')
? argv[++i] : true;
args[key] = value;
}
}
return args;
}
function formatBytes(bytes) {
const units = ['B', 'KB', 'MB', 'GB'];
let i = 0;
let size = bytes;
while (size >= 1024 && i < units.length - 1) {
size /= 1024;
i++;
}
return `${size.toFixed(2)} ${units[i]}`;
}
function getSystemInfo() {
const cpus = os.cpus();
const totalMem = os.totalmem();
const freeMem = os.freemem();
return {
hostname: os.hostname(),
platform: os.platform(),
arch: os.arch(),
osType: os.type(),
cpuModel: cpus[0].model,
cpuCores: cpus.length,
totalMemory: formatBytes(totalMem),
freeMemory: formatBytes(freeMem),
memUsage: ((totalMem - freeMem) / totalMem * 100).toFixed(1) + '%',
uptime: (os.uptime() / 3600).toFixed(1) + ' hours'
};
}
function getEnvInfo(keys) {
const result = {};
for (const key of keys) {
result[key] = process.env[key] || '(未设置)';
}
return result;
}
function printReport(sys, env) {
const sep = '='.repeat(48);
console.log(`\n${sep}`);
console.log(' 系统诊断报告');
console.log(`${sep}`);
console.log(` 主机名 : ${sys.hostname}`);
console.log(` 平台 : ${sys.platform} / ${sys.arch}`);
console.log(` 操作系统 : ${sys.osType}`);
console.log(` CPU : ${sys.cpuModel}`);
console.log(` CPU 核心数 : ${sys.cpuCores}`);
console.log(` 总内存 : ${sys.totalMemory}`);
console.log(` 可用内存 : ${sys.freeMemory}`);
console.log(` 内存使用率 : ${sys.memUsage}`);
console.log(` 运行时间 : ${sys.uptime}`);
console.log(`${sep}`);
console.log(' 环境变量');
console.log('-'.repeat(48));
for (const [key, val] of Object.entries(env)) {
console.log(` ${key.padEnd(20)} : ${val}`);
}
console.log(`${sep}\n`);
}
const args = parseArgs(process.argv);
const envKeys = args.envKeys
? args.envKeys.split(',')
: ['NODE_ENV', 'HOME', 'PATH', 'SHELL'];
const sys = getSystemInfo();
const env = getEnvInfo(envKeys);
printReport(sys, env);
node syscheck.js --envKeys NODE_ENV,APP_PORT,DATABASE_URL
================================================
系统诊断报告
================================================
主机名 : web-server-01
平台 : linux / x64
操作系统 : Linux
CPU : Intel(R) Xeon(R) CPU E5-2680 v4
CPU 核心数 : 8
总内存 : 15.88 GB
可用内存 : 6.23 GB
内存使用率 : 60.7%
运行时间 : 72.5 hours
================================================
环境变量
------------------------------------------------
NODE_ENV : production
APP_PORT : (未设置)
DATABASE_URL : (未设置)
================================================
❓ 常见问题
📖 小节
- os 模块提供系统级信息:CPU、内存、平台、网络接口、用户信息等
- process.argv 解析命令行参数,argv[0] 是 Node 路径,argv[1] 是脚本路径
- process.env 管理环境变量,dotenv 库从 .env 文件加载配置
- process.exit() 需谨慎使用,避免跳过清理逻辑
- process.nextTick() 属于微任务,优先于 setImmediate 和 Promise
- 使用 os.EOL、os.sep、path.join 处理跨平台差异
📝 作业
- 编写脚本,输出当前系统的 CPU 核心数、总内存(GB)、可用内存(GB)和内存使用百分比
- 使用 process.argv 实现一个简易命令行计算器,支持
--add、--sub、--mul三种运算 - 创建 .env 文件存储数据库连接信息,用 dotenv 加载并在脚本中安全读取(提供默认值)
- 实现一个函数,检测当前平台是否为 Windows,若是则使用
\r\n换行符,否则使用\n - 编写脚本,监控内存使用率,当超过 90% 时向 stderr 输出警告信息