如何設置node全局腳本

前語

隨着node的流行,JS已經能夠解決大部分問題。這對前端工程師十分友好。
相信不少同窗在開發業務之餘,都會寫一些小腳本代替手工完成繁瑣,重複的工做,從而提升工做效率。
但部分同窗開發的腳本,僅侷限於腳本所在路徑,經過node xxx 去運行程序,這侷限了腳本的使用範圍和使用便捷性。css

本文就給你們介紹一個簡單且一勞永逸的方法,把本身開發的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除了美觀,還能夠起到警示的做用。需呀
  • 基本用法:node

    // 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,第二個成員是腳本文件名,其他成員是腳本文件的參數。
  • 基本用法:linux

    let elem1 = process.argv[2]; // 攜帶的參數一
    let elem2 = process.argv[3]; // 攜帶的參數二

調用linux命令

  • 介紹:有時候咱們須要的功能並非僅靠node就能實現的,還須要linux命令作支持。那怎麼經過node調用Linux命令呢?
  • 基本用法:git

    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命令打開頁面便可。
  • 基本用法:github

    require('child_process').exec(`open http://baidu.com`); // 打開百度shell

    // 這是網上找到的,兼容各運行環境的打開頁面方法
    let cmd = ''; // 運行的指令
    if (process.platform == 'wind32') {
      cmd = 'start "%ProgramFiles%\Internet Explorer\iexplore.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這個腳本,執行它。
    這和咱們日常在終端裏面執行有什麼區別呢?
    在終端裏面,咱們調用命令是攜帶上下文的。即第二條命令會在執行完第一條命令以後的環境下執行,例如npm

    cd /
    ls

    這兩條命令是先切換到根路徑,再打印跟路徑下的文件信息。
    若是像上面同樣,經過gulp

    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\n' + arguments)); }); // 消息的錯誤監聽
    subProcess.on('close', (code) => { // 關閉bash進程後觸發的事件
    if (code === 0) {
        console.log(colors.blue(`執行成功!`));
    } else {
        console.log(colors.blue(`執行失敗,錯誤碼爲:${code}`));
    }
    }); // 監聽進程退出
    //向子進程發送命令
    subProcess.stdin.write(`cd / \n`);   // 切換目錄,\n表示回車,執行cd命令
    subProcess.stdin.write(`ls -a \n`);   // 寫入數據
    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 + `\n`;
    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}】\n`;
    }
    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\n' + 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 \n`); // 切換pwd
    Process.stdin.write(`gulp default --${inputPath} --${outputPath} \n`); // 執行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 \n'); // 切換pwd
        Process.stdin.write('gulp reload --${watchList.join(',')} \n'); // 執行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\n' + 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} \n`);   // 寫入數據
subProcess.stdin.end();

還有其餘的,像什麼「一鍵git」「一鍵svn」,這些就根據實際須要組合開發啦。

問題求助

筆者在開發腳本時,遇到兩個問題,有興趣的大神能夠指點指點

文件夾

複製剪切板和scp的衝突

這是「一鍵上傳文件或文件夾到服務器」遇到的問題,複製剪切板和scp命令會衝突,若是放在同一個bash進程執行會失敗,沒找到緣由。

linux應答式異步交互,實現ssh的一鍵登陸。

這個功能我用linux的shell腳本實現過。可是放在node沒能找到實現思路,

相關文章
相關標籤/搜索