广告位 · 页头(后台-模块管理-新建模块后替换此区域)

如何用Node.js将ifconfig输出转换为Mock2Image图片?

网络排查时,ifconfig是Linux和macOS上查看接口配置的首选命令。它输出的文本包含网卡名称、IPv4和IPv6地址、MAC地址、收发统计等关键信息,但直接复制到聊天工具里往往换行错乱,截图又受字体和分辨率影响不够清晰。借助Node.js,可以把这段纯文本转换为结构清晰的图片,Mock2Image就是面向这一需求的轻量渲染思路。本文从命令执行、文本解析到图片生成完整拆解,给出可落地的代码。

如何用Node.js将ifconfig输出转换为Mock2Image图片?

解析ifconfig输出中的网络接口数据

执行ifconfig本身并不复杂,困难在于不同系统的输出格式差异明显。Linux的net-tools包输出的接口块之间通常有一个空行,macOS的BSD风格则可能连续排列。因此第一步要拿到原始文本。在Node.js中,可以使用child_process模块的execFile方法运行命令,避免exec带来的shell注入风险。下面的代码展示了如何异步执行ifconfig并拿到标准输出。

const { execFile } = require('child_process');
function runIfconfig() {
  return new Promise((resolve, reject) => {
    execFile('ifconfig', [], { encoding: 'utf8' }, (error, stdout, stderr) => {
      if (error) {
        reject(stderr || error.message);
        return;
      }
      resolve(stdout);
    });
  });
}

拿到文本后,需要把它拆分成独立的接口块。一个实用的做法是按连续空行进行分隔,然后针对每个块用正则表达式提取字段。接口名通常出现在块首行,格式为eth0:或en0:;IPv4地址出现在inet之后;MAC地址则跟在ether或hwaddr后面。RX和TX的字节数可以从bytes字段中解析出来。下面是一个兼容Linux和macOS常见格式的解析函数。

function parseIfconfig(output) {
  const interfaces = [];
  // 不同系统按空行分隔接口块
  const blocks = output.split(/\n\n+/).filter(b => b.trim() !== '');
  for (const block of blocks) {
    const lines = block.split('\n');
    const nameMatch = lines[0].match(/^(\S+):/);
    if (!nameMatch) continue;
    const name = nameMatch[1];
    const info = { name };
    const inet = block.match(/inet\s+([0-9.]+)/);
    if (inet) info.ipv4 = inet[1];
    const inet6 = block.match(/inet6\s+([0-9a-fA-F:]+)/);
    if (inet6) info.ipv6 = inet6[1];
    const ether = block.match(/ether\s+([0-9a-fA-F:]+)/);
    if (ether) info.mac = ether[1];
    const rxBytes = block.match(/RX packets\s+\d+\s+bytes\s+(\d+)/);
    const txBytes = block.match(/TX packets\s+\d+\s+bytes\s+(\d+)/);
    info.rxBytes = rxBytes ? parseInt(rxBytes[1], 10) : 0;
    info.txBytes = txBytes ? parseInt(txBytes[1], 10) : 0;
    interfaces.push(info);
  }
  return interfaces;
}

解析过程中有两个常见的坑需要留意。第一,某些精简Linux发行版没有安装net-tools,ifconfig会直接报错,此时需要提醒用户改用ip addr并调整正则表达式。第二,macOS的接口块之间可能没有空行,只靠\n\n+分割会漏掉数据,更稳妥的做法是先按行扫描,遇到以字母开头且后面紧跟冒号的行就认为是新接口块。生产环境建议结合平台检测,对Linux和macOS分别处理。

设计Mock2Image图片渲染器

Mock2Image的核心思路是把命令行输出模拟成一张信息清晰、样式统一的图片。实现这个目标有多种方案:使用Puppeteer截图会把简单问题复杂化,依赖浏览器体积太大;使用SVG转PNG虽然灵活,但需要额外的转换库;直接用node-canvas在Canvas上绘制文本则是最直观的方式。node-canvas在服务端实现了与浏览器Canvas相似的API,可以设置字体、颜色、背景,并直接导出PNG Buffer。

渲染器需要规划布局。顶部放置标题如ifconfig summary,下方按接口逐个绘制卡片,每个卡片包含接口名称、IPv4、MAC、收发字节数。等宽字体是命令行氛围的关键,可以使用Noto Sans Mono或系统自带的monospace。如果服务器没有安装中文字体,需要提前把字体文件放入项目并通过registerFont注册。下面的代码展示了一个基础渲染函数。

const { createCanvas } = require('canvas');
async function renderToImage(interfaces, originalText, width, height) {
  const canvas = createCanvas(width, height);
  const ctx = canvas.getContext('2d');
  ctx.fillStyle = '#1e1e1e';
  ctx.fillRect(0, 0, width, height);
  ctx.font = 'bold 22px "Noto Sans Mono", monospace';
  ctx.fillStyle = '#ffffff';
  ctx.fillText('ifconfig summary', 30, 50);
  let y = 100;
  for (const item of interfaces) {
    ctx.font = 'bold 18px monospace';
    ctx.fillStyle = '#4fc3f7';
    ctx.fillText(item.name, 30, y);
    y += 26;
    ctx.font = '15px monospace';
    ctx.fillStyle = '#c8e6c9';
    ctx.fillText('IPv4: ' + (item.ipv4 || 'n/a'), 50, y);
    y += 24;
    ctx.fillText('MAC: ' + (item.mac || 'n/a'), 50, y);
    y += 24;
    ctx.fillText('RX bytes: ' + item.rxBytes, 50, y);
    y += 24;
    ctx.fillText('TX bytes: ' + item.txBytes, 50, y);
    y += 42;
  }
  return canvas.toBuffer('image/png');
}

实际使用中,图片高度不能写死,否则接口多时内容会被截断。建议根据接口数量动态计算高度,每个接口卡片预留150到200像素。如果需要高清输出,可以创建两倍尺寸的Canvas,然后将绘制内容整体缩放两倍,这样在Retina屏幕上文字边缘会更锐利。Mock2Image还可以扩展主题配置,比如深色和浅色模式、自定义强调色,以及是否在图片底部附上原始纯文本的小字块,方便对照。

整合完整流程与跨平台兼容处理

把命令执行、解析、渲染串起来,就是一个完整的小工具。主函数负责捕获异常、检查是否解析到有效数据、生成图片并写入文件。下面的代码展示了整合后的入口逻辑,其中runIfconfig和renderToImage可以拆到独立模块中,也可以放在同一个文件里方便快速测试。

const fs = require('fs');
async function main() {
  try {
    const raw = await runIfconfig();
    const interfaces = parseIfconfig(raw);
    if (interfaces.length === 0) {
      throw new Error('未解析到任何网络接口,请确认系统是否安装了ifconfig');
    }
    const imageBuffer = await renderToImage(interfaces, raw, 900, 600 + interfaces.length * 160);
    fs.writeFileSync('ifconfig-mock2image.png', imageBuffer);
    console.log('图片已生成:ifconfig-mock2image.png');
  } catch (err) {
    console.error('生成失败:', err.message);
    process.exit(1);
  }
}
main();

跨平台兼容方面,Windows系统并没有ifconfig命令,而是使用ipconfig。要支持Windows,需要检测process.platform,在win32下调用ipconfig /all并编写另一套解析逻辑。对于Linux,如果目标机器只有iproute2工具,也可以回退到ip -o addr show,再用类似的正则抽取数据。不要把解析逻辑写成单一正则匹配全部输出,保持每个平台独立函数会让维护成本更低。

部署到无头服务器时,要注意node-canvas依赖系统级图形库,例如Ubuntu需要安装libcairo2-dev、libpango1.0-dev等包。如果无法安装系统依赖,可以改用纯JavaScript的图片编码库,或者退回到生成SVG文本再由其他服务转换。性能方面,单次生成一张900x800的PNG通常耗时在几十毫秒,适合作为诊断接口的即时响应,但不建议在热点路径中频繁调用。通过缓存字体和复用Canvas实例,可以进一步降低开销。

这个方案的价值不止于ifconfig。掌握了从子进程输出到结构化数据,再到图片渲染的流程后,你可以快速复制到其他命令行工具,比如把df -h、free -m或自定义监控脚本的输出转成适合分享的图片,让运维信息传递更直观。

广告位 · 文章底部(后台-模块管理替换此区域)