【Node.JS】使用子进程监听文件并执行系统命令

功能描述

1、使用 node.js 监听文本文件。
2、监听到文件改变后创建子进程。
3、在子进程中执行系统命令。

问题描述

1、windows 环境下,监听过程中,报错 “spawn dir ENOENT”。
2、windows 环境下,最终系统命令输出的结果乱码。

主要代码

'use strict'		//开启严格模式

/* 引入 node.js 的 fs 模块 */
const fs = require('fs');
/* 引入 node.js 的 child_process 模块下的 spawn 方法 */
/* 因为本例中只使用到 spawn 方法, 所以建议只引入使用到的方法 */
const spawn = require('child_process').spawn;
//或者 import { spawn } from 'child_process';

/* 访问命令行输入的参数。参数为数组类型 */
/* 在本例中,索引[0]为 node 的绝对路径,[1]为该 node.js 文件的绝对路径, [2]为手动指定的目标文件名路径 */
const filename = process.argv[2];

if(!filename){
	throw Error('A file to watch must be specified !');
}

/* 开启监听 */
/* watch 方法需要两个参数。1、需要监听的目标文件路径;2、监听的回调方法 */
/* 本例中,回调方法使用箭头函数。() 表示空参 */
fs.watch(filename, () => {
	/* spawn 方法执行系统命令 */
	/* 该方法有三个参数,后两个参数为可选参数。1、执行的命令;2、参数数组;3、配置信息对象 */
	//const ls = spawn('ls', ['-l', '-h', filename]);//linux 下的命令。相当于 ls -l -h filename
	const ls = spawn('dir', ['-w', filename]);//windows 下的命令,相当于 dir /w filename
	/* spawn 方法返回的对象是 ChildProcess。其 stdin、stdout、stderr 属性都是 Stream ,可以直接输出 */
	/* 使用 pipe 方法将子进程中的输出内容传送到标准输出流 */
	ls.stdout.pipe(process.stdout);
});
console.log(`Now watching ${filename} for changed...`);

调试过程

1、创建监听目标文件 target.txt;
2、保存上述代码到同目录下 watcher.js
3、以 windows 环境为例,打开 cmd 命令行,执行如下命令,发现报错。

F:\NodeJS\filesystem> node watcher.js target.txt
Now watching target.txt for changed...
events.js:182
	throw er; // Unhandled 'error' event
	^
Error: spawn dir ENOENT    
	at exports._errnoException (util.js:1026:11)    
	at Process.ChildProcess._handle.onexit (internal/child_process.js:189:19)    
	at onErrorNT (internal/child_process.js:366:16)   
	 at _combinedTickCallback (internal/process/next_tick.js:102:11)    
	 at process._tickCallback (internal/process/next_tick.js:161:9)

报错原因分析:
错误提示:ENOENT。
其一般为:No such file was found or the specified path name doesn’t exist 的错写。
即:没有找到文件,或者指定的路径名不存在。

一般,执行 spawn 命令时遇到该报错,最常见的原因有两个:
1、参数不匹配。当前命令下没有这个参数。
2、运行环境发生变化时,当前环境下不存在这个命令。

检查一遍,似乎发现上述代码现在是在 windows 环境下运行,执行的是 dir /w 命令
似乎并没有问题。

但是,忽略了一点。在 windows 环境下,cmd 命令也是需要显示的去指派的。
也就是说,我们需要先调用 cmd 下的 dir 命令: spawn(‘cmd’, [‘dir’])
在较新的版本的 node.js 中,可以直接配置 shell:true 属性来控制是否调用 shell。

/* 即将上面的代码换成如下:增加一个 shell 的配置项。其值可以直接写为 true */
/* 但在本例中,令其值为 (当前环境是否为 windows 环境?) 的一个 bool 值 */
const ls = spawn('dir', ['-w', filename], {shell:process.platform === 'win32'});

再次运行 node 调用该 js 文件

F:\NodeJS\filesystem> node watcher.js target.txt
Now watching target.txt for changed... 
	������ F �еľ��� code 
	�������� F2A6-190E
 F:\NodeJS\filesystem ��Ŀ¼target.txt               
 	1 ���ļ�             37 �ֽ�
 	0 ��Ŀ¼ 209,791,561,728 �����ֽ� 
������ F �еľ��� code 
�������� F2A6-190E

乱码的问题在 cmd 中已经不少见了。
老规矩,先确认 cmd 的编码规则。运行如下命令

F:\NodeJS\filesystem>chcp
活动代码页: 936

可以看到,936:GBK。也是 cmd 的默认编码。而 node.js 默认输出的是 UTF-8
修改 cmd 的编码为 UTF-8

F:\NodeJS\filesystem>chcp 65001
Active code page: 65001

重新运行 watcher.js 启用监听

F:\NodeJS\filesystem>node watcher.js target.txt
Now watching target.txt for changed... 
	Volume in drive F is code 
	Volume Serial Number is F2A6-190E

	Directory of F:\NodeJS\filesystem
target.txt
	1 File(s)             39 bytes               
	0 Dir(s)  209,791,561,728 bytes free
Volume in drive F is code 
Volume Serial Number is F2A6-190E

乱码问题已经没有了。
但需要注意的是,在 cmd 中修改编码仅对当前窗口有效,下次打开 cmd 需要重新设置。

如果想 cmd 保持某一编码,需要在设置完编码后,打开属性 --> 选项 --> 勾选"丢弃旧的副本"选项。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

HolaSecurity

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值