资讯专栏INFORMATION COLUMN

如何设置node全局脚本

cgspine / 1246人阅读

摘要:全局脚本设置的本质思路其实原理很简单将的全局命令搜索路径,加上脚本所在文件夹的路径。权限设置了以后,脚本的图标将变成下面这个样子。重启或新建终端,执行脚本。

前语

随着node的流行,JS已经可以解决大部分问题。这对前端工程师十分友好。
相信很多同学在开发业务之余,都会写一些小脚本代替手工完成繁琐,重复的工作,从而提高工作效率。
但部分同学开发的脚本,仅局限于脚本所在路径,通过node xxx 去运行程序,这局限了脚本的使用范围和使用便捷性。

本文就给大家介绍一个简单且一劳永逸的方法,把自己开发的node脚本部署在全局环境。让脚本可以像Linux命令一样,全局便捷地使用,从此打开新世界的大门。

全局脚本设置的本质思路 其实原理很简单:将Linux的全局命令搜索路径,加上脚本所在文件夹的路径。

具体设置过程 找到终端配置文件

终端配置文件默认路径为「/User/用户名」,笔者的mac用户名为Momo,故以下示例中用户名均为「Momo」。

原配终端为bash,对应配置文件为「.bash.rc」。装了zsh终端的同学,对应修改「.zsh.rc」。

解析:.rc文件为终端的配置文件,在重启终端,或者新开终端tab都会读取该文件。

修改Linux的全局命令搜索路径

打开文件,加上脚本所在文件夹。笔者的脚本均放在了myShell(其实应该叫myScript)文件夹中,所以加上一句export PATH=/Users/Momo/myShell:$PATH

解析:在Linux中,全局命令搜索路径就是通过PATH变量保存起来的。「:」是字符串链接符的意思。类似于js中,var str = "1" + "2";中的「+」

修改js脚本文件

在头部加上#!/usr/bin/env node"use strict";

解析:#!/usr/bin/env node是指本脚本是通过「/usr/bin/env」路径下的node软件运行。相当于文件中什么软件打开。"use strict";是指使用js的严格语法。

注意这两句一定要放置为js文件顶部,否则系统将不知道用什么软件执行。运行失败

修改js脚本文件权限

终端运行chmod 777 脚本文件名,如示例chmod 777 mop

解析:chmod是linux下修改文件权限的工具,777代表所有读写权限。具体的百度chmod即可。权限设置了以后,脚本的图标将变成下面这个样子。

重启或新建终端,执行脚本。

解析:重启或新建终端是为了读取到刚修改的终端配置文件,让Linux的全局命令搜索路径生效。遍历到我们所开发的脚本。

脚本常用功能 设置不同颜色的console.log

介绍:不同颜色的log除了美观,还可以起到警示的作用。

基本用法:

// colors不是Node自带模块,需要事先npm install colors安装
const colors = require("colors"); // 引用colors模块,常用颜色    black,red,green,yellow,blue,magenta,cyan,white,gray,grey
console.log(colors.red("filePath or targetPath can not be empty!")); // 在控制台输出红色的文案

获取终端所在目录路径

介绍:如题所示,获取终端当前所在目录,而不是脚本所在路径

基本用法:let basePath = process.cwd(); // 其中process是node全局变量,提供当前 Node 进程的信息

携带参数运行脚本

介绍:平时我们使用linux命令都会伴随一些参数,那么在node中怎么实现,怎么获取运行时携带的参数呢?通过process.argv即可,它将返回一个数组,由命令行执行脚本时的各个参数组成。它的第一个成员总是node,第二个成员是脚本文件名,其余成员是脚本文件的参数。

基本用法:

let elem1 = process.argv[2]; // 携带的参数一
let elem2 = process.argv[3]; // 携带的参数二

调用linux命令

介绍:有时候我们需要的功能并不是仅靠node就能实现的,还需要linux命令做支持。那怎么通过node调用Linux命令呢?

基本用法:

const child_process = require("child_process"); // child_process是node负责子进程的模块
child_process.exec("ls -a", function (error, stdout, stderr) { // 通过child_process下的exec函数执行linux命令
    error && console.log("error  " + error); // 执行出错时的错误信息
    console.log("Child Process STDOUT: " + stdout); // stdout是执行linux命令后的执行   结果。在这里即返回执行ls -a命令遍历到的文件信息   
});

打开页面

介绍:怎么通过Node用浏览器打开特定页面呢?mac自带了open命令,我们通过node调用open命令打开页面即可。

基本用法:

require("child_process").exec(`open http://baidu.com`); // 打开百度

// 这是网上找到的,兼容各运行环境的打开页面方法
let cmd = ""; // 运行的指令
if (process.platform == "wind32") {
  cmd = "start "%ProgramFiles%Internet Exploreriexplore.exe"";
} else if (process.platform == "linux") {
  cmd = "xdg-open";
} else if (process.platform == "darwin") {
  cmd = "open";
}
require("child_process").exec(`${cmd} http://baidu.com`);

携带上下文执行linux命令

介绍:上面介绍到的调用linux方法,本质上只是直接去调用具体的Linux命令。如调用ls,相当于直接找到系统里面ls这个脚本,执行它。
这和我们平常在终端里面执行有什么区别呢?
在终端里面,我们调用命令是携带上下文的。即第二条命令会在执行完第一条命令之后的环境下执行,例如

cd /
ls

这两条命令是先切换到根路径,再打印跟路径下的文件信息。
如果像上面一样,通过

require("child_process").exec(`cd /`);
require("child_process").exec(`ls`);

则只是执行了两个相互独立的命令,一个是切换目录,一个是打印文件信息。ls打印的不是切换目录后的文件信息,而是运行脚本时所在的文件信息。
那怎么携带上下文执行linux命令呢?

基本用法:

// 注意,这里使用到了colors模块,用于显示不同颜色的输出。不需要的话,也可以直接console.log()打印。
const subProcess = require("child_process").spawn("bash"); // 使用子程序去运行某个软件,在这里就是运行bash软件。相当于运行一个终端
subProcess.stdout.on("data", function(data) { console.log(colors.green(data)); }); // 监听命令执行后,bash返回的信息
subProcess.on("error", function() { console.log(colors.red("error
" + arguments)); }); // 消息的错误监听
subProcess.on("close", (code) => { // 关闭bash进程后触发的事件
if (code === 0) {
    console.log(colors.blue(`执行成功!`));
} else {
    console.log(colors.blue(`执行失败,错误码为:${code}`));
}
}); // 监听进程退出
//向子进程发送命令
subProcess.stdin.write(`cd / 
`);   // 切换目录,
表示回车,执行cd命令
subProcess.stdin.write(`ls -a 
`);   // 写入数据
subProcess.stdin.end(); // 结束进程,相当于关闭终端

将某数据复制到剪切板

介绍:这是一个很常用的功能

基本用法:

const copyProcess = require("child_process").spawn("bash"); // 用于复制密码的进程
copyProcess.stdin.write(`echo ${Config.server.password} | pbcopy`); // 将特定文本拷贝到剪切板中
copyProcess.stdin.end(); // 结束进程

常用脚本

上面介绍了一些基本的node功能,虽然看似很简答。但如果善于运用,也可以做出一些提高效率的小工具。

mhelp,一键查看自定义文档

功能介绍:自定义常用文档,方便地查看。例如markdown语法,常用全局匹配的正则什么的。省的重复打开笔记。

基本思路:「colors颜色控制」+「携带参数运行脚本」

示例代码:

#!/usr/bin/env node
"use strict";
const colors = require("colors"); // 命令行颜色black,red,green,yellow,blue,magenta,cyan,white,gray,grey
let helpName = process.argv[2]; // 需要查看的文档名
let helpInfo = {
    markdown: {
        "无需列表": ".1 xxx  .1 xxx    .1 xxx",
        "有需列表": "- xxx   - xxx   - xxx",
    }
}; // 自定义帮助文档
// 设置文档name为他本身
let allHelpName = "";
let match = false; // 是否找到匹配项
for (let helpItem in helpInfo) {
    allHelpName += helpItem + `
`;
    if (helpItem === helpName) {
        match = true;
        for (let detailItem in helpInfo[helpItem]) {
            console.log(colors.green(detailItem + " : " + helpInfo[helpItem][detailItem])); // 找不到页面相关信息
        }
        return;
    }
}
if (!match) {
    console.log(colors.red("can not find matched helpInfo!    the all helpName is")); // 找不到页面相关信息
    console.log(colors.red(allHelpName)); // 找不到页面相关信息
}
mop,一键打开常用页面并复制密码到剪切板

功能介绍:简单,一个命令打开特定页面,而且帮你把特定文案复制到剪切板。例如?登陆密码。

基本思路:「复制剪切板」+「打开页面」+「colors颜色控制」

示例代码:

#!/usr/bin/env node
"use strict";
const proess = require("child_process");
const copyProcess = proess.spawn("bash"); // 用于复制密码的进程,为了避免同一个进程拷贝和上传时的冲突
const colors = require("colors"); // 命令行颜色black,red,green,yellow,blue,magenta,cyan,white,gray,grey
const dataInfo = require("../config").dataInfo;
const introduce = require("../config").shellInfo["mop"].introduce; // 脚本介绍,用在momoShell中介绍
let dataName = process.argv[2]; // 需要打开的页面
let onlyShow = process.argv[3]; // 是否只显示数据,不打开页面
let dataItem = dataInfo[dataName]; // 遍历成功后获取的页面对象
// 输入脚本简介
if (process.argv[2] === "-h") {
    console.log(colors.green(introduce));
    copyProcess.stdin.end();
    return;
}
// 检测数据有效性
if (!dataName) { // 参数为空
    console.log(colors.red("dataName can not be empty!"));
    copyProcess.stdin.end();
    return;
} else if (!dataItem) { // 找不到页面信息
    let allDataName = "";
    for (let dataItem in dataInfo) {
        allDataName += `${dataItem}【${dataInfo[dataItem].info}】
`;
    }
    console.log(colors.red("can not find matched dataInfo!    the all dataName is")); // 找不到页面相关信息
    console.log(colors.red(allDataName)); // 找不到页面相关信息
    copyProcess.stdin.end();
    return;
}
console.log(colors.green(`【name】${dataItem.name}`));
dataItem.account && console.log(colors.green(`【account】${dataItem.account}`));
dataItem.password && console.log(colors.green(`【password】${dataItem.password}`));
dataItem.url && console.log(colors.green(`【url】${dataItem.url}`));
// 将密码拷贝到剪切板中
copyProcess.stdin.write(`echo ${dataItem.password} | pbcopy`);   // 写入数据
copyProcess.stdin.end();
!onlyShow && dataItem.url && require("child_process").exec(`open ${dataItem.url}`); // 打开特定页面
mgulp,一键gulp打包项目,一键动态刷新

功能介绍:解决了每个项目都需要配置gulp及其依赖的麻烦。功能就如标题所说,一键gulp打包项目,一键动态刷新(需结合livereload工具)

基本思路:「携带参数运行脚本」+「携带上下文执行linux命令」

示例代码:(这里还需结合gulpfile.js文件一起使用,详情请查看笔者github上的文件结构)

#!/usr/bin/env node
"use strict";
const Process = require("child_process").spawn("bash"); // 使用子程序去运行某个软件。在这里就是运行bash软件。并获取其上下文。
const colors = require("colors"); // 命令行颜色black,red,green,yellow,blue,magenta,cyan,white,gray,grey
const Config = require("../config"); // 服务器信息
const introduce = Config.shellInfo["mgulp"].introduce; // 脚本介绍,用在momoShell中介绍
const elem = process.argv; // 输入的参数
const basePath = process.cwd();
const action = elem[2]; // 文件名
// 消息监听,监听子进程的输出。并在主进程中打印出来。
function onData(data) { console.log(colors.green(data)); }
// 设置消息监听
Process.stdout.on("data", onData);
Process.on("error", function() { console.log(colors.red("error
" + arguments)); });
Process.on("close", (code) => {
    if (code === 0) {
        console.log(colors.blue(`执行成功!`));
    } else {
        console.log(colors.blue(`执行成功失败,错误码为:${code}`));
    }
}); // 监听进程退出
if (action === "-h") { // 输入脚本简介
    console.log(colors.green(introduce));
    return;
} else if (action === "-publish") { // 输入脚本简介
    let inputPath = basePath + "/" + (elem[3] || ""); // 文件输入
    let outputPath = basePath + "/" + elem[4]; // 文件输出
    if (!elem[4]) {
        outputPath = basePath + `/a-gulp-publish/${elem[3]}`;
    }
    Process.stdin.write(`cd /Users/Momo/Desktop/intruction/Node/shell 
`); // 切换pwd
    Process.stdin.write(`gulp default --${inputPath} --${outputPath} 
`); // 执行gulp,通过「--」来让gulp不解析为gulp任务
    Process.stdin.end();
} else if (action === "-watch") { // 输入脚本简介
    let watchList = elem[3];
    if (!watchList) {    // 检测数据有效性
        console.log(colors.red("watchList can not be empty!"));
    } else {
        watchList = watchList.split(",").map((item) => { // 格式化路径
            item = basePath + "/" + item;
            item.replace(////g, "/"); // 去除双斜杠
            if (item.indexOf("*") === -1) { // 监听所有文件,及旗下文件夹内的文件
                item = item + "/*.*," + item + "/*/*.*";
            }
            return item;
        });
        Process.stdin.write("cd /Users/Momo/Desktop/intruction/Node/shell 
"); // 切换pwd
        Process.stdin.write("gulp reload --${watchList.join(",")} 
"); // 执行gulp
        Process.stdin.end();
    }
} else { // 输入脚本简介
    console.log(colors.red("please input action"));
    Process.stdin.end();
}
mupload,一键上传文件或文件夹到服务器

功能介绍:如题,可上传整个文件夹,不需要打开ftp软件这么麻烦(注意scp命令不支持强制覆盖文件夹功能)

基本思路:「复制剪切板」+「调用linux命令」+ 「scp命令」

示例代码:

#!/usr/bin/env node
"use strict";
const colors = require("colors"); // 命令行颜色black,red,green,yellow,blue,magenta,cyan,white,gray,grey
const Config = require("../config"); // 服务器信息
const copyProcess = require("child_process").spawn("bash"); // 用于复制密码的进程,为了避免同一个进程拷贝和上传时的冲突
const subProcess = require("child_process").spawn("bash"); // 使用子程序去运行某个软件。在这里就是运行bash软件。并获取其上下文。
const introduce = Config.shellInfo["mupload"].introduce; // 脚本介绍,用在momoShell中介绍
let elem = process.argv; // 输入的参数
let basePath = process.cwd();
let filePath = basePath + "/" + elem[2]; // 文件名
let targetPath = elem[3]; // 目标路径
// 将服务器密码拷贝到剪切板中
copyProcess.stdin.write(`echo ${Config.server.password} | pbcopy`);   // 写入数据
copyProcess.stdin.end();
// 输入脚本简介
if (process.argv[2] === "-h") {
    console.log(colors.green(introduce));
    copyProcess.stdin.end();
    subProcess.stdin.end();
    return;
}
// 检测数据有效性
if (!filePath || !targetPath) {
    console.log(colors.red("filePath or targetPath can not be empty!"));
    subProcess.stdin.end();
    return;
}
// 兼容目标路径
if (targetPath[targetPath.length - 1] === "/") {
    if (elem[2].indexOf("/") !== -1) {
        targetPath += elem[2].substr(elem[2].indexOf("/") + 1);
    } else {
        targetPath += elem[2];
    }
}
// 消息监听,监听子进程的输出。并在主进程中打印出来。
function onData(data) { console.log(colors.green(data)); }
//设置消息监听
subProcess.stdout.on("data", onData);
subProcess.on("error", function() { console.log(colors.red("error
" + arguments)); });
subProcess.on("close", (code) => {
    if (code === 0) {
        console.log(colors.blue(`上传成功!`));
        console.log(colors.red(`注意,上传文件夹并不会覆盖原文件,请登录服务器查看文件是否替换成功`));
    } else {
        console.log(colors.blue(`上传失败,错误码为:${code}`));
    }
}); // 监听进程退出
//向子进程发送命令
subProcess.stdin.write(`scp -C -r -p ${filePath} root@${Config.server.ip}:${targetPath} 
`);   // 写入数据
subProcess.stdin.end();
还有其他的,像什么「一键git」「一键svn」,这些就根据实际需要组合开发啦。 问题求助

笔者在开发脚本时,遇到两个问题,有兴趣的大神可以指点指点

复制剪切板和scp的冲突

这是「一键上传文件或文件夹到服务器」遇到的问题,复制剪切板和scp命令会冲突,如果放在同一个bash进程执行会失败,没找到原因。

linux应答式异步交互,实现ssh的一键登录。

这个功能我用linux的shell脚本实现过。但是放在node没能找到实现思路,

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/92619.html

相关文章

  • 深入浅出Node.js

    摘要:深入浅出一直想致力于写一篇关于广义讲解系统的文章,苦于时间有限,资源有限。事件驱动机制是通过内部单线程高效率地维护事件循环队列来实现的,没有多线程的资源占用和上下文的切换。 深入浅出Node.js 一直想致力于写一篇关于广义讲解Node.js系统的文章,苦于时间有限,资源有限。这篇文章是在结合自己的学习心得以及与行业大佬共同探讨下争对于熟练掌握JS语言后的广义Node.js.至于为什么...

    oujie 评论0 收藏0
  • 深入浅出Node.js

    摘要:深入浅出一直想致力于写一篇关于广义讲解系统的文章,苦于时间有限,资源有限。事件驱动机制是通过内部单线程高效率地维护事件循环队列来实现的,没有多线程的资源占用和上下文的切换。 深入浅出Node.js 一直想致力于写一篇关于广义讲解Node.js系统的文章,苦于时间有限,资源有限。这篇文章是在结合自己的学习心得以及与行业大佬共同探讨下争对于熟练掌握JS语言后的广义Node.js.至于为什么...

    MadPecker 评论0 收藏0
  • 深入浅出Node.js

    摘要:深入浅出一直想致力于写一篇关于广义讲解系统的文章,苦于时间有限,资源有限。事件驱动机制是通过内部单线程高效率地维护事件循环队列来实现的,没有多线程的资源占用和上下文的切换。 深入浅出Node.js 一直想致力于写一篇关于广义讲解Node.js系统的文章,苦于时间有限,资源有限。这篇文章是在结合自己的学习心得以及与行业大佬共同探讨下争对于熟练掌握JS语言后的广义Node.js.至于为什么...

    lily_wang 评论0 收藏0
  • 深入浅出Node.js

    摘要:深入浅出一直想致力于写一篇关于广义讲解系统的文章,苦于时间有限,资源有限。事件驱动机制是通过内部单线程高效率地维护事件循环队列来实现的,没有多线程的资源占用和上下文的切换。 深入浅出Node.js 一直想致力于写一篇关于广义讲解Node.js系统的文章,苦于时间有限,资源有限。这篇文章是在结合自己的学习心得以及与行业大佬共同探讨下争对于熟练掌握JS语言后的广义Node.js.至于为什么...

    DandJ 评论0 收藏0
  • nodejs 基础篇整合

    摘要:基础篇整合最近有朋友也想学习相关方面的知识,如果你是后端想接近前端,作为一门跑在服务端的语言从这里入门再好不过了。事件驱动机制是通过内部单线程高效率地维护事件循环队列来实现的,没有多线程的资源占用和上下文的切换。 nodeJs 基础篇整合 最近有朋友也想学习nodeJs相关方面的知识,如果你是后端想接近前端,node作为一门跑在服务端的JS语言从这里入门再好不过了。如果你正好喜欢前端,...

    lemanli 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<