告别跨平台脚本烦恼:ShellJS让Node.js轻松调用Unix命令
你还在为编写跨平台的脚本而头疼吗?还在纠结Windows批处理与Linux Shell的语法差异吗?本文将带你掌握ShellJS的全部核心用法,让你用熟悉的JavaScript语法写出在任何操作系统都能运行的命令行工具。读完本文,你将能够:
- 使用JavaScript调用ls、cp、rm等Unix命令
- 编写跨Windows、macOS和Linux的脚本
- 掌握文件操作、目录管理的实用技巧
- 处理命令输出和错误信息
- 构建完整的自动化工作流
ShellJS简介:Node.js的Unix命令工具箱
ShellJS是一个为Node.js提供可移植Unix shell命令的库,它让你可以在JavaScript中使用熟悉的命令行操作,而无需担心跨平台兼容性问题。无论是文件操作、目录管理还是系统命令执行,ShellJS都能轻松胜任。
项目核心文件结构清晰,主要命令实现位于src/目录下,每个命令对应一个单独的文件,如src/ls.js实现列表功能,src/cp.js处理文件复制。这种模块化设计使得代码易于维护和扩展。
快速开始:安装与基础配置
安装ShellJS
使用npm或yarn即可轻松安装ShellJS:
# 本地安装(推荐)
npm install shelljs
# 全局安装(如需命令行使用)
npm install -g shelljs
根据package.json文件显示,当前稳定版本为0.8.3,需要Node.js 18或更高版本支持。
基础使用方法
在项目中引入ShellJS后,你就可以开始使用各种Unix命令了:
// 标准引入方式
const shell = require('shelljs');
// 检查是否安装了git
if (!shell.which('git')) {
// 使用echo命令输出信息
shell.echo('Error: 本脚本需要git支持');
// 退出程序并返回错误码
shell.exit(1);
}
这种方式不会污染全局命名空间,是推荐的使用方式。
核心命令详解
文件与目录操作
ShellJS提供了完整的文件和目录操作命令,语法与Unix命令类似,但通过JavaScript调用。
列出文件与目录
使用ls命令可以列出指定路径的文件和目录:
// 列出当前目录所有文件
const files = shell.ls();
// 列出所有.js文件
const jsFiles = shell.ls('*.js');
// 递归列出所有文件
const allFiles = shell.ls('-R', 'src/');
命令实现位于src/ls.js,支持-R(递归)、-A(显示隐藏文件)等常用选项。
创建与删除目录
mkdir命令用于创建目录,支持-p选项创建多级目录:
// 创建单个目录
shell.mkdir('newdir');
// 创建多级目录
shell.mkdir('-p', 'a/b/c/d');
对应的实现文件为src/mkdir.js。删除目录则使用rm命令:
// 删除文件
shell.rm('file.txt');
// 递归删除目录及内容
shell.rm('-rf', 'directory/');
删除功能由src/rm.js实现,注意-r和-f选项的组合使用。
文件内容操作
读取文件内容
使用cat命令可以读取文件内容,实现位于src/cat.js:
// 读取单个文件
const content = shell.cat('file.txt');
// 读取多个文件并合并内容
const combined = shell.cat('file1.txt', 'file2.txt');
返回的是ShellString对象,可以直接转换为字符串或进行后续处理。
查找内容
grep命令可以在文件中查找匹配的内容,实现位于src/grep.js:
// 在.js文件中查找包含"function"的行
const results = shell.grep('function', '*.js');
// 忽略大小写查找
const caseInsensitive = shell.grep('-i', 'ERROR', 'log.txt');
支持-v(反向匹配)、-i(忽略大小写)等常用选项。
高级文件操作
复制与移动文件
cp命令用于复制文件,实现位于src/cp.js:
// 复制单个文件
shell.cp('source.txt', 'destination.txt');
// 递归复制目录
shell.cp('-R', 'src/', 'dist/');
// 仅复制更新的文件
shell.cp('-u', '*.html', 'public/');
移动文件则使用mv命令(src/mv.js):
// 移动文件
shell.mv('oldname.txt', 'newname.txt');
// 移动多个文件到目录
shell.mv(['file1.txt', 'file2.txt'], 'backup/');
文件权限管理
chmod命令用于修改文件权限,实现位于src/chmod.js:
// 使用数字权限设置
shell.chmod(755, 'script.sh');
// 使用符号权限设置
shell.chmod('u+x', 'script.sh');
// 递归修改目录权限
shell.chmod('-R', 'a-w', 'docs/');
流程控制与高级功能
目录切换与路径管理
cd命令用于切换工作目录,实现位于src/cd.js:
// 切换到指定目录
shell.cd('src/');
// 切换到用户主目录
shell.cd('~');
// 返回上一次目录
shell.cd('-');
配合pwd命令(src/pwd.js)可以获取当前工作目录:
// 获取当前目录
const currentDir = shell.pwd();
shell.echo(`当前目录: ${currentDir}`);
执行外部命令
exec命令允许你执行系统命令,实现位于src/exec.js:
// 同步执行命令并获取输出
const version = shell.exec('node --version', { silent: true }).stdout;
// 异步执行长时间运行的命令
const child = shell.exec('npm install', { async: true });
child.stdout.on('data', (data) => {
console.log(`输出: ${data}`);
});
// 执行命令并检查退出码
if (shell.exec('git commit -am "Auto-commit"').code !== 0) {
shell.echo('Error: Git commit failed');
shell.exit(1);
}
命令输出重定向
ShellJS支持类似Unix的输出重定向功能:
// 将内容写入文件(覆盖模式)
shell.echo('Hello World').to('output.txt');
// 将内容追加到文件
shell.echo('Append this line').toEnd('output.txt');
// 管道操作:查找并替换内容
shell.cat('input.txt').grep('pattern').sed('old', 'new').to('output.txt');
实用场景示例
项目构建脚本
以下是一个典型的项目构建脚本示例,展示了如何组合多个命令实现自动化流程:
const shell = require('shelljs');
// 清理旧构建目录
if (shell.test('-d', 'dist/')) {
shell.rm('-rf', 'dist/');
}
// 创建新的构建目录
shell.mkdir('-p', 'dist/js', 'dist/css', 'dist/images');
// 复制HTML文件
shell.cp('src/*.html', 'dist/');
// 处理JavaScript文件
shell.cd('src/js');
// 合并JS文件并输出到dist目录
shell.cat('*.js').to('../../dist/js/bundle.js');
shell.cd('../..');
// 复制CSS文件
shell.cp('src/css/*.css', 'dist/css/');
// 压缩图片(需要安装imagemin-cli)
if (shell.which('imagemin')) {
shell.exec('imagemin src/images/* --out-dir=dist/images');
} else {
// 如果没有安装imagemin,直接复制图片
shell.cp('src/images/*', 'dist/images/');
}
shell.echo('构建完成!');
版本发布脚本
结合Git命令,我们可以创建一个自动化的版本发布脚本:
const shell = require('shelljs');
const version = '1.2.3'; // 可以从参数或package.json读取
// 检查工作区是否干净
if (shell.exec('git diff --quiet').code !== 0) {
shell.echo('Error: 工作区有未提交的更改');
shell.exit(1);
}
// 运行测试
shell.echo('运行测试...');
if (shell.exec('npm test').code !== 0) {
shell.echo('Error: 测试失败');
shell.exit(1);
}
// 更新版本号
shell.exec(`npm version ${version} --no-git-tag-version`);
// 构建项目
shell.exec('npm run build');
// 提交更改
shell.exec(`git add package.json package-lock.json dist/`);
shell.exec(`git commit -m "chore: 发布版本 ${version}"`);
shell.exec(`git tag v${version}`);
// 推送更改和标签
shell.exec('git push origin main');
shell.exec(`git push origin v${version}`);
// 发布到npm
shell.exec('npm publish');
shell.echo(`成功发布版本 ${version}`);
错误处理与调试
错误处理最佳实践
ShellJS提供了多种错误处理机制,帮助你构建健壮的脚本:
// 方法一:检查命令返回码
const result = shell.rm('nonexistent.txt');
if (result.code !== 0) {
shell.echo(`Error: 删除文件失败 - ${result.stderr}`);
}
// 方法二:使用error()检查上一个命令是否出错
shell.rm('nonexistent.txt');
if (shell.error()) {
shell.echo('Error: 删除文件失败');
}
// 方法三:设置全局错误退出
shell.set('-e'); // 等同于shell.config.fatal = true
// 以下命令失败时将直接退出
shell.rm('nonexistent.txt');
// 后续代码不会执行
调试技巧
使用verbose模式可以帮助你调试脚本:
// 开启详细输出模式
shell.set('-v'); // 等同于shell.config.verbose = true
// 所有命令都会输出到控制台
shell.cd('src');
shell.ls('*.js');
shell.exec('npm test');
总结与进阶
通过本文的介绍,你已经掌握了ShellJS的核心用法和最佳实践。从简单的文件操作到复杂的构建流程,ShellJS都能帮助你用JavaScript编写出跨平台的脚本工具。
项目的完整文档可以参考README.md,更多高级用法和插件开发指南可以查看官方Wiki。如果你想深入了解某个命令的实现细节,可以查阅src/目录下的对应文件。
ShellJS已经被众多知名项目采用,包括Firebug、JSHint、ESLint等,证明了其稳定性和可靠性。现在,是时候用ShellJS来简化你的开发流程,告别繁琐的批处理脚本,用JavaScript的力量提升你的工作效率了!
最后,不要忘记给项目点赞和贡献代码,一起完善这个优秀的工具库!
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考



