标签: shell

  • NODEJS 命令行工具开发简介

    SHELL可执行脚本

    写一个 shell 命令行脚本。

    # test001.sh
    echo "Hello World !"

    如何运行这个脚本?

    sh test001.sh

    这还不是一个命令行工具,这里命令行工具是 sh,test001.sh 是这个工具的一个参数。

    如何转转换成命令行工具?

    # test001.sh
    #!/bin/bash
    echo "Hello World !"
    chmod +x test001.sh

    以命令行工具的形式执行。

    ./test001.sh

    和平常的命令行工具有点不一样?

    重命名成 test001,放入系统路径中,就可以直接用 test001 全局执行命令。

    export PATH="/usr/local/opt/ruby/bin:$PATH"

    复杂多文件的情况?

    test001
    |--bin/
    |----test001
    |--lib/
    |----...
    export PATH="/path/to/test001/bin:$PATH"

    扩展一

    cat /etc/shells
    # List of acceptable shells for chpass(1).
    # Ftpd will not allow users to connect who are not using
    # one of these shells.
    # /bin/false was added for FTP users that do not have a home directory.
    /bin/bash
    /bin/csh
    /bin/ksh
    /bin/sh
    /bin/tcsh
    /bin/zsh
    /usr/bin/false

    扩展二

    #!/usr/bin/env shell

    1、兼容性,/usr/bin/env 从系统路径中查找脚本解释器路径

    2、/usr/bin/env 有 -S -P 参数,可以指定其他查找路径

    #!/usr/bin/env -S -P /custom/search/path:${PATH} bash

    NODEJS 可执行脚本

    同理

    # test002.js
    console.log('hello world');
    node test002.js
    # test002.js
    #!/usr/bin/env node
    console.log('hello world');
    chmod +x test002.js 
    ./test002.js

    去扩展名,复杂多文件的情况?

    # aveng/meili-all-fwtool-aides Aides 3 项目
    .
    ├── bin
    │   ├── aides
    │   ├── aides_application
    │   ├── aides_component
    │   ├── aides_fwtool
    │   ├── enums
    │   └── tools
    ├── jsconfig.json
    ├── lib
    │   ├── application
    │   ├── commons
    │   ├── component
    │   ├── fwtool
    │   └── index.js
    ├── node_modules
    |   |...
    ├── package-lock.json
    ├── package.json
    ├── src
    │   ├── application
    │   ├── commons
    │   ├── component
    │   ├── fwtool
    │   └── index.js
    ├── README.md
    └── yarn.lock

    扩展一

    对 nodejs 命令行工具,不需要手动设置系统路径

    {
      "name": "test002",
      "bin": {
        "test002": "path/to/entry\ file"
      }
    }
    npm link

    NODEJS 命令行工具开发

    获取命令行参数

    1、普通方式

    在 nodejs 脚本中,通过 process.argv 获取命令行参数,process.argv 是个数组:

    #!/usr/bin/env node
    console.log('process.argv: ', process.argv);
    node test001.js -a -b -c -d 123 --aaa --bbb --ccc --ddd 123 456
    process.argv:  [ '/usr/local/Cellar/node/11.3.0_1/bin/node',
      '/Users/eqielb/Test/test/test001.js',
      '-a',
      '-b',
      '-c',
      '-d',
      '123',
      '--aaa',
      '--bbb',
      '--ccc',
      '--ddd',
      '123',
      '456' ]
    ./test001.js -a -b -c -d 123 --aaa --bbb --ccc --ddd 123 456

    输出结果是一样的。

    2、commander 模块

    手动分析管理参数非常麻烦,可以使用 commander 模块

    https://www.npmjs.com/package/commander

    3、 yargs 模块

    https://www.npmjs.com/package/yargs

    4、 minimist 模块

    https://www.npmjs.com/package/minimist

    5、模块对比

    调用系统其他命令

    1、基础模块

    可以通过 nodejs 的 child_process 模块,新建子进程执行其他命令

    #!/usr/bin/env node
    var name = process.argv[2];
    var exec = require('child_process').exec;
    
    var child = exec('echo hello ' + name, function(err, stdout, stderr) {
        if (err) throw err;
        console.log(stdout);
    });
    2、通用模块

    如:安装 shelljs 模块

    #!/usr/bin/env node
    var name = process.argv[2];
    var shell = require("shelljs");
    
    shell.exec("echo hello " + name);

    如:安装 execa 模块

    const execa = require('execa');
    
    (async () => {
        const {stdout} = await execa('echo', ['unicorns']);
        console.log(stdout);
        //=> 'unicorns'
    })();

    模块对比:

    3、特定模块

    如: 安装 nodegit 模块

    var Git = require("nodegit");
    // Clone a given repository into the ./tmp folder.
    Git.Clone("https://github.com/nodegit/nodegit", "./tmp")
        // Look up this known commit.
        .then(function(repo) {
            // Use a known commit sha from this repository.
            return repo.getCommit("59b20b8d5c6ff8d09518454d4dd8b7b30f095ab5");
        })

    命令行交互

    1、inquirer 包

    美化控制台输出

    1、chalk、colors 包

    2、ora 包、cli-spinners

    3、blessed-contrib 包

    https://github.com/yaronn/blessed-contrib

    4、命令行字体 figlet

     _ __ ___    ___    __ _  _   _
    | '_  _ \  / _ \  / _ || | | |
    | | | | | || (_) || (_| || |_| |
    |_| |_| |_| \___/  \__, | \__,_|
                       |___/

    其他事项

    1、返回值

    根据 Unix 传统,程序执行成功返回 0,否则返回 1 。

    if (err) {
        process.exit(1);
    } else {
        process.exit(0);
    }
    process.exitCode = 1; 
    process.exit(); // 默认情况下 exitCode 是 0

    扩展一

    process.exit 有回调方法

    process.on('exit', (code) => {
       // 同步方法 
        console.log(About to exit with code: ${</span><span class="cm-variable-2">code</span><span class="cm-string-2">});
    });

    扩展二

    一般情况下,不建议直接调用 process.exit() 方法,直接调用会导致异步方法中断。需要手动异常退出的话,可以设置 process.exitCode ,并抛出 uncaught error,让进程根据异常自动退出。

    2、重定向
    ps aux | grep 'node'

    nodejs 中实现这种功能

    process.stdin.resume();
    process.stdin.setEncoding('utf8');
    process.stdin.on('data', function(data) {
        process.stdout.write(data);
    });
    3、系统信号

    接受系统信号

    process.on('SIGINT', function () {
      console.log('Got a SIGINT');
      process.exit(0);
    });

    发送系统信号

    kill -s SIGINT [process_id]

    扩展

    这些功能开发不太常用,运维会用到,看公司发布系统的脚本

    发布

    命令行工具就是一个 npm 包,执行 npm publish 进行发布,npm i 安装后就可以使用。

    NODEJS 命令行工具应用举例

    1、主机管理

    aws、google cloud、aliyun、qcloud 等都支持 oauth 2.0认证,可以命令行下做验证通过命令行管理服务。

    2、命令行爬虫

    3、自动提交表单

  • 批量替换 github 的 https 连接为 ssh 连接

    要把 git repo 的 https 连接方式改成 ssh 的一般有两种方法:
    一、修改 repo 下 .git 文件夹里的 config 文件,将 [remote "origin"] 里的 https://github.com/ 改成 git@github.com:
    二、使用 git 提供的命令来修改 git remote set-url origin git@github.com:user/repo.git
    两种方法不做修改的话都没法实现批量处理,对整个 workspace 内那么多 repo 没个批量处理的方法那还不疯了。
    其实批量处理也很简单啦,一条命令的事情,就是对上面的方法一作一些小修改,用了三个比较常用的命令 find, grep, sed
    $ find ~/workspace -exec grep "https://github.com/" ‘{}’ ; -exec sed -i "" "s^https://github.com/^git@github.com:^g" {} ;
    查找文件夹下所有文件,找到其中的 https://github.com/ 替换成 git@github.com: