Node.js: os 与 process 模块

最后更新:2026-08-26

Alice 是一名 DevOps 工程师,负责管理数十台服务器。每次部署新应用时,她都要手动登录服务器检查 CPU 核心数、可用内存、操作系统版本,再根据环境变量切换配置。一天凌晨 3 点的紧急部署中,她因手动检查遗漏了内存不足的问题导致部署失败。于是她决定用 Node.js 写一个自动检测脚本,一键获取服务器资源和环境信息,让部署不再踩坑。

1. 你将学到



2. os 模块:系统信息采集

(1) CPU 与内存信息

os.cpus() 返回 CPU 核心详细信息数组,os.totalmem()os.freemem() 分别返回总内存和可用内存(单位:字节)。

▶ 示例:检测服务器 CPU 与内存

JAVASCRIPT
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}%`);
▶ 试一试
TEXT 📖 仅展示
CPU 核心数: 8
CPU 型号: Intel(R) Core(TM) i7-9700K CPU @ 3.60GHz
总内存: 15.88 GB
可用内存: 6.23 GB
内存使用率: 60.7%

(2) 操作系统标识

os.platform() 返回平台标识(如 win32linuxdarwin),os.type() 返回操作系统名称,os.arch() 返回 CPU 架构,os.hostname() 返回主机名。

▶ 示例:获取操作系统信息

JAVASCRIPT
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()}`);
▶ 试一试
TEXT 📖 仅展示
平台: linux
系统类型: Linux
CPU 架构: x64
主机名: web-server-01
系统版本: #1 SMP Thu Jan 1 00:00:00 UTC 2026

(3) 用户与目录信息

os.userInfo() 返回当前用户信息,os.homedir() 返回用户主目录,os.tmpdir() 返回临时文件目录。

▶ 示例:获取用户与目录信息

JAVASCRIPT
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()}`);
▶ 试一试
TEXT 📖 仅展示
用户名: alice
主目录: /home/alice
Shell: /bin/bash
临时目录: /tmp

(4) 网络接口信息

os.networkInterfaces() 返回所有网络接口的详细信息,包括 IP 地址、MAC 地址和地址族。

▶ 示例:查看网络接口

JAVASCRIPT
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})`);
    }
  }
}
▶ 试一试
TEXT 📖 仅展示
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] 是被执行的脚本路径,后续元素是传入的命令行参数。

100%
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' }"]

▶ 示例:解析命令行参数

JAVASCRIPT
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);
▶ 试一试
BASH
node cli.js --env production --port 8080 --verbose
TEXT 📖 仅展示
{ env: 'production', port: '8080', verbose: true }

(2) 环境变量 process.env

process.env 包含所有环境变量的键值对,是部署脚本判断运行环境的核心依据。

▶ 示例:读取与设置环境变量

JAVASCRIPT
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}`);
▶ 试一试
TEXT 📖 仅展示
NODE_ENV: development
PATH: /usr/local/bin:/usr/bin:/bin
APP_MODE: production

(3) 进程退出与工作目录

process.exit(code) 终止进程(0 表示成功,非 0 表示失败),process.cwd() 返回当前工作目录。

▶ 示例:条件退出与目录检查

JAVASCRIPT
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)} 秒`);
▶ 试一试
TEXT 📖 仅展示
缺少必需环境变量: DATABASE_URL, APP_SECRET

(4) 标准流:stdin / stdout / stderr

process.stdoutprocess.stderr 是可写流,process.stdin 是可读流,用于与终端交互。

▶ 示例:使用标准流输出与输入

JAVASCRIPT
process.stdout.write('请输入您的名称: ');

process.stdin.once('data', (data) => {
  const name = data.toString().trim();
  process.stdout.write(`你好, ${name}!\n`);
  process.exit(0);
});
▶ 试一试
TEXT 📖 仅展示
请输入您的名称: Alice
你好, Alice!

(5) process.nextTick()

process.nextTick() 将回调放入微任务队列,在当前操作完成后、I/O 事件之前执行,常用于确保异步操作按预期顺序进行。

▶ 示例:nextTick 执行顺序

JAVASCRIPT
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');
});
▶ 试一试
TEXT 📖 仅展示
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

JAVASCRIPT
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'));
▶ 试一试
TEXT 📖 仅展示
换行符转义: "\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 文件:

TEXT 📖 仅展示
NODE_ENV=production
DATABASE_URL=postgresql://db.example.com:5432/myapp
APP_SECRET=my-super-secret-key
APP_PORT=3000

在代码中加载:

JAVASCRIPT
require('dotenv').config();

console.log(`环境: ${process.env.NODE_ENV}`);
console.log(`数据库: ${process.env.DATABASE_URL}`);
console.log(`端口: ${process.env.APP_PORT}`);
TEXT 📖 仅展示
环境: 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) 安全读取环境变量

▶ 示例:带验证的环境变量读取

JAVASCRIPT
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

JAVASCRIPT 📖 仅展示
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);
逻辑代码 76 行(超过 40 行限制,仅展示)
BASH
node syscheck.js --envKeys NODE_ENV,APP_PORT,DATABASE_URL
TEXT 📖 仅展示
================================================
  系统诊断报告
================================================
  主机名     : 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         : (未设置)
================================================

❓ 常见问题

Q process.argv[0] 和 process.argv[1] 分别是什么?
A argv[0] 是 Node.js 可执行文件的路径(如 /usr/local/bin/node),argv[1] 是被执行的脚本文件路径(如 /home/alice/app.js),实际用户传入的参数从 argv[2] 开始。
Q 如何安全地读取环境变量?
A 始终提供默认值或做存在性检查,对数值类型进行转换和验证,使用 dotenv 管理 .env 文件,切勿将 .env 提交到版本控制。
Q os.freemem() 返回的是什么单位?
A 返回字节数(bytes),如需 GB 显示需手动除以 1073741824(即 1024×1024×1024),也可用格式化函数自动换算。
Q 如何在 Node.js 中读取用户输入?
A 使用 process.stdin 可读流配合 data 事件监听,或使用 readline 模块提供的逐行读取接口,readline 更适合交互式问答场景。
Q process.exit() 为什么要谨慎使用?
A process.exit() 会立即终止进程,跳过所有待执行的回调、I/O 操作和清理逻辑,可能导致数据丢失或资源未释放,应优先让事件循环自然结束。
Q process.nextTick() 和 setImmediate() 有什么区别?
A nextTick 回调在微任务队列中,当前操作后立即执行且优先于所有 I/O;setImmediate 在宏任务队列中,在 I/O 事件循环阶段执行,nextTick 优先级更高。
Q dotenv 的 .env 文件应该放在哪里?
A 默认放在项目根目录,可通过 config({ path: 'custom/path' }) 指定路径,务必将 .env 加入 .gitignore 防止敏感信息泄露。

📖 小节


📝 作业

  1. 编写脚本,输出当前系统的 CPU 核心数、总内存(GB)、可用内存(GB)和内存使用百分比
  2. 使用 process.argv 实现一个简易命令行计算器,支持 --add--sub--mul 三种运算
  3. 创建 .env 文件存储数据库连接信息,用 dotenv 加载并在脚本中安全读取(提供默认值)
  4. 实现一个函数,检测当前平台是否为 Windows,若是则使用 \r\n 换行符,否则使用 \n
  5. 编写脚本,监控内存使用率,当超过 90% 时向 stderr 输出警告信息
Web-Tutorial.com

Web-Tutorial 技术团队

由多位开发者共同维护的编程教程平台。每篇教程由对应领域的开发者编写和审核,确保内容准确可靠。如发现任何问题,欢迎向我们反馈。

100%

🙏 帮我们做得更好

我们是刚上线的编程教程站,几个人的小团队,精力有限。页面虽经检查,难免还有疏漏——链接失效、排版错乱、内容有误、语言生硬……

如果您发现了,麻烦告诉我们,我们会在收到反馈后第一时间进行修复,再次感谢您的光临 🙏