关于命令行:修改windows10命令行的字符编码

windows命令行启动elasticsearch时,命令行字符乱码,须要批改编码格局:有两种, 一种是长期, 一种是永恒批改注册表: 1. 长期批改输出【win+r】->chcp 65001->确定2. 批改注册表1. 关上注册表: 输出【win+r】,regedit 确定;2. 门路【HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Command Processor】3. 【新建->字符串值】名称=autorun, 值=chcp 65001

December 28, 2022 · 1 min · jiezi

关于命令行:inquirer命令行交互原理一readline的实现方法和原理

背景目前在开发ohh-cli脚手架,当中有用到了inquirer来实现命令行的交互;在好奇心的驱动下,想去钻研下它的执行和原理。 知识点readline/events/stream/ansi-escapes/rxjs指标把握命令行交互的实现,并实现一个可交互的列表 一、readline的实现办法和原理1. readlie介绍node的内置库,次要是治理输出流;监听键盘上所有按钮的操作;node官网的形容:https://nodejs.org/dist/lates... The node:readline module provides an interface for reading data from a Readable stream (such as process.stdin) one line at a time.翻译:readline模块提供了一个接口,用于每次一行从可读流(如process.stdin)读取数据。2.readlie的应用readlie.js const readline = require ('readline');const rl = readline.createInterface({ input: process.stdin, // ( process.stdin:零碎输出流 ); output: process.stdout // ( process.stdout: 零碎输入流 );})// 交互命令rl.question('your name:', answer => { console.log(answer); rl.close(); // readline 不会主动敞开,须要调用命令敞开})node执行js your name:ohhohhreadline 是依据传入的输出流信息,逐行读取,按回车后,认为输出信息曾经完结;再将输出流的信息传入到输入流output中,进行展现; 3.readline源码重点浏览3.1 readlie的整个过程的筹备工作(1) 强制将函数转化为构造函数 functuon createInterface(input, output, completer, terminal) { return Interface(input, output, completer, terminal);}function Interface(input, output, completer, terminal) { // Instanceof判断一个对象的正确类型,外部机制是通过原型链来判断的,测试一个对象在其原型链中是否存在一个构造函数的prototype属性。 if(!(this instanceof Interface)) { // false 就强制转化 return new Interface(input, output, completer, terminal) }}(2) readlie如何去做事件监听的 ...

August 21, 2022 · 3 min · jiezi

关于命令行:测试开发之网络篇常用命令

ipconfigWindows零碎下,ipconfig加上/all参数,可查看本机的IP地址、掩码、默认网关、DHCP和DNS服务器等信息。Linux或Mac零碎下,请应用ifconfig命令代替。 C:\Users\admin>ipconfig /allWindows IP ConfigurationEthernet adapter Ethernet0: Connection-specific DNS Suffix . : DHCP Description . . . . . . . . . . . : Intel(R) 82574L Gigabit Network Connection Physical Address. . . . . . . . . : 00-0C-29-A8-3E-AA DHCP Enabled. . . . . . . . . . . : Yes Autoconfiguration Enabled . . . . : Yes Link-local IPv6 Address . . . . . : fe80::547b:2b11:b2bd:3cfb%15(Preferred) IPv4 Address. . . . . . . . . . . : 172.16.13.3(Preferred) Subnet Mask . . . . . . . . . . . : 255.255.255.0 Lease Obtained. . . . . . . . . . : 2021年5月24日 14:26:49 Lease Expires . . . . . . . . . . : 2021年5月25日 14:12:25 Default Gateway . . . . . . . . . : 172.16.13.1 DHCP Server . . . . . . . . . . . : 172.16.13.1 DHCPv6 IAID . . . . . . . . . . . : 117443625 DHCPv6 Client DUID. . . . . . . . : 00-01-00-01-25-1B-98-1F-00-0C-29-A8-3E-AA DNS Servers . . . . . . . . . . . : 172.16.13.1 NetBIOS over Tcpip. . . . . . . . : Enabled Connection-specific DNS Suffix Search List : DHCP HOSTping能够用来检测达到另一个主机的连通性,并获取以下信息。留神,有些机器可能会禁用ping所用的ICMP协定,导致没有响应。 ...

July 9, 2021 · 2 min · jiezi

关于命令行:windowLinuxMacOS-命令行

Linux/MacOS 命令: 留神,因为有些命令在 Linux 中有 MacOS 没有,网上找到的有时候比拟含糊,所以不肯定完全正确,我尽量辨别不同的。 符号的含意:符号含意&vert;管道符&&代表 and 同时运行多个命令, 应用它。\容许您在新行中持续编写命令 Bash语法。*匹配门路下,所有文件或者文件夹名称<< EOF [重定向文件] ...内容 EOF分界符, EOF 不肯定是 它,只是通常用它作为分界符标识 ; 联合cat进行内容的追加>获取命令的规范输入并将其重定向到一个文件中(将笼罩整个文件)2>获取命令的谬误输入并将其重定向到一个文件中(将笼罩整个文件)&>获取命令的规范和谬误输入并将其重定向到一个文件中(将笼罩整个文件)<将文件的内容读入命令的输出>>将文本或命令规范输入追加到文件的最初一行2>>将文本或命令谬误输入追加到文件的最初一行&>>将文本或命令规范和谬误输入追加到文件的最初一行花括号扩大:在传统的 shell 中是没有 花括号扩大这个性能的. $ echo a{p,c,d,b}e# 输入后果: ape ace ade abe$ echo {a,b,c}{d,e,f}# 输入后果: ad ae af bd be bf cd ce cf$ ls *.{jpg,jpeg,png} # 首先扩大为*.jpg *.jpeg *.png,而后解析通配符 当花括号扩大和变量扩大一起应用时,变量扩大解析于花括号扩大之后。有时有必要应用内置的 eval 函数: $ start=1; end=10$ echo {$start..$end} # 因为解析程序,无奈失去想要的后果# 输入后果: {1..10}$ eval echo {$start..$end} # 首先进行变量扩大的解析# 输入后果: 1 2 3 4 5 6 7 8 9 10bash 中 ``, '', "" 区别: 首先它们都能够用来解决bash 中字符串中的空格问题。 ...

November 16, 2020 · 3 min · jiezi

命令行录制工具-asciinema

平常出bug求助的时候有时候贴代码或者截图往往不直观,如果能重现给对方看就好了,这里推荐 2 个命令行的录制工具。 asciinema网站https://asciinema.org/ ,github主页https://github.com/asciinema 直接使用 pip install asciinema 来安装。 执行asciinema rec 开始录制,录制完成后 exit 退出,可以保存到本地或者上传到 https://asciinema.org 。 [root@VM_0_14_centos ~]# asciinema recasciinema: recording asciicast to /tmp/tmp1ua5a2rx-ascii.castasciinema: press <ctrl-d> or type "exit" when you're done[root@VM_0_14_centos ~]# pwd/root[root@VM_0_14_centos ~]# cd /usr/share/nginx/html/[root@VM_0_14_centos html]# pip install asciinemaDEPRECATION: Python 3.4 support has been deprecated. pip 19.1 will be the last one supporting it. Please upgrade your Python as Python 3.4 won't be maintained after March 2019 (cf PEP 429).Looking in indexes: http://mirrors.tencentyun.com/pypi/simpleRequirement already satisfied: asciinema in /usr/lib/python3.4/site-packages (2.0.2)You are using pip version 19.0.3, however version 19.1.1 is available.You should consider upgrading via the 'pip install --upgrade pip' command.[root@VM_0_14_centos html]# pip list |grep asciiDEPRECATION: Python 3.4 support has been deprecated. pip 19.1 will be the last one supporting it. Please upgrade your Python as Python 3.4 won't be maintained after March 2019 (cf PEP 429).asciinema 2.0.2You are using pip version 19.0.3, however version 19.1.1 is available.You should consider upgrading via the 'pip install --upgrade pip' command.[root@VM_0_14_centos html]# exitexitasciinema: recording finishedasciinema: press <enter> to upload to asciinema.org, <ctrl-c> to save locallyView the recording at: https://asciinema.org/a/AdnqMX0QfOg5c7USOtwHZ4Hz1This installation of asciinema recorder hasn't been linked to any asciinema.orgaccount. All unclaimed recordings (from unknown installations like this one)are automatically archived 7 days after upload.If you want to preserve all recordings made on this machine, connect thisinstallation with asciinema.org account by opening the following link: https://asciinema.org/connect/01fb0f0e-c56a-450f-80ac-4020188dd957录制过程在https://asciinema.org/a/AdnqM... 可以看到了。 ...

July 9, 2019 · 3 min · jiezi

比-man-更强悍的命令行工具-cheat

经常使用命令行,比如 curl 测试接口响应时间 for i in {1..10};do curl -o /dev/null -s -w "$i | time_namelookup: %{time_namelookup} | time_connect: %{time_connect} | time_starttransfer: %{time_starttransfer} | time_total: %{time_total}\n" "http://httpbin.org/ip";done1 | time_namelookup: 0.016000 | time_connect: 0.016000 | time_starttransfer: 0.125000 | time_total: 0.1410002 | time_namelookup: 0.016000 | time_connect: 0.016000 | time_starttransfer: 0.094000 | time_total: 0.1090003 | time_namelookup: 0.016000 | time_connect: 0.031000 | time_starttransfer: 0.109000 | time_total: 0.1090004 | time_namelookup: 0.015000 | time_connect: 0.031000 | time_starttransfer: 0.109000 | time_total: 0.1090005 | time_namelookup: 0.031000 | time_connect: 0.031000 | time_starttransfer: 0.109000 | time_total: 0.1090006 | time_namelookup: 0.016000 | time_connect: 0.016000 | time_starttransfer: 0.094000 | time_total: 0.1090007 | time_namelookup: 0.016000 | time_connect: 0.016000 | time_starttransfer: 0.125000 | time_total: 0.1250008 | time_namelookup: 0.000001 | time_connect: 0.016000 | time_starttransfer: 0.141000 | time_total: 0.1410009 | time_namelookup: 0.015000 | time_connect: 0.015000 | time_starttransfer: 0.093000 | time_total: 0.10900010 | time_namelookup: 0.000001 | time_connect: 0.015000 | time_starttransfer: 0.109000 | time_total: 0.125000奈何命令行参数太多,记不住怎么办?这时候你需要个男人,它就是 man ...

June 29, 2019 · 6 min · jiezi

git命令行对比本地仓库跟远程仓库

通常团队合作一个项目,如果项目中有人push代码到远程仓库,我们用git的gui客户端会获取到远程仓库更新了什么,但是没有合并,也就是说没有merge。 但是用git的命令怎么实现呢? git fetch (从远程的origin仓库的master分支下载代码到本地的origin master。如果要指定仓库和分支:git fetch origin master)git log -p master.. origin/master(比较本地的仓库和远程仓库的区别,—name-only:不显示文件详细更改信息)

June 28, 2019 · 1 min · jiezi

转每个Web开发者都该了解的12条命令行

本文转自葡萄城控件,原文出处在开发者的弹药箱里,命令行是最具生产力的工具之一。掌握它们可以给你的工作流程带来非常积极的影响。因为,许多日常任务都可以用一条命令然后按回车来解决。 在本文中,我们为你准备了一系列常用命令,帮你充分利用你的终端。这其中有些命令是系统内置的,另外的一些则是需要另外安装的免费工具,不过这些免费工具是经历了时间的考验,所以你可以分分钟将他们安装完成。 curlcurl是一个发送请求的命令行工具。可使用HTTP(s)、FTP,以及一些你可能从未听过的协议发送请求。它可以下载文件,检查响应头,自由地访问远程数据。 在web开发中,curl常用于测试连接和RESTful APIs。 # 获取一个URL的HTTP HEADERcurl -I http://google.comHTTP/1.1 302 FoundCache-Control: privateContent-Type: text/html; charset=UTF-8Referrer-Policy: no-referrerLocation: http://www.google.com/?gfe_rd=cr&ei=0fCKWe6HCZTd8AfCoIWYBQContent-Length: 258Date: Wed, 09 Aug 2017 11:24:01 GMT# 向远程API发出GET请求curl http://numbersapi.com/random/trivia29 is the number of days it takes Saturn to orbit the Sun.curl命令可以远比上面的情况复杂。它有一大堆的选项来控制请求头、cookies、权限验证等等。你可以在这本相当棒的免费书Everything curl中读到更多。 treetree是一个小巧的命令行,用于可视化地展示目录里的文件结构。它递归地执行,检查嵌套的每一个层级,为所有内容绘制出格式化的树形结构。你可以用它快速浏览文件结构,定位到所需的文件。 tree.├── css│ ├── bootstrap.css│ ├── bootstrap.min.css├── fonts│ ├── glyphicons-halflings-regular.eot│ ├── glyphicons-halflings-regular.svg│ ├── glyphicons-halflings-regular.ttf│ ├── glyphicons-halflings-regular.woff│ └── glyphicons-halflings-regular.woff2└── js ├── bootstrap.js └── bootstrap.min.js也有类似正则匹配的选项,用于过滤结果。 tree -P '*.min.*'.├── css│ ├── bootstrap.min.css├── fonts└── js └── bootstrap.min.jstmux根据维基百科所说,tmux是一个终端复用器,翻译为人话就是说,它是一个把多给终端连接为一个终端会话的工具。 ...

June 4, 2019 · 1 min · jiezi

一个简单的-命令行-图片压缩工具

一个简单的 命令行 图片压缩工具https://tinyjpg.com/ 是一个图片压缩网站, 在进行图片压缩的同时非常好的保存了图片的质量. 相信做前端的同学很多都用到过. 偶然一次发现该网站有提供Developer API , 点开一看还发现有很多已经封装好的第三方package. 但这些package都是提供编程时使用的, 很多时候我们需要的是快速压缩一两张图片, 而不是编写脚本去执行代码. 所以为了方面命令行使用, 我将其封装成了一个 global 的npm包. 安装后即可全局使用. 使用方式安装该命令行工具 npm install -g @ssthouse/img-compress设置 API key (注: API key 需要在 tiniyjpg网站 进行申请, 提供用户名和邮箱即可得到一个 500次/ 每月 的key) img-compress init -key your_api_key如果你的terminal网络需要使用代理的话, 需要进行设置: img-compress proxy http://example.com开始压缩图片 img-process img_file命令执行成功后会在原图的同一目录看到压缩过的图片文件. 文件名以 __compress.文件后缀 结尾. 如: test.png => test_compress.png 查看使用说明不带参数的执行该工具就可以看到使用说明, 如有遇到问题可以在这里提issue: @ssthouse/img-compress 最后如果你对我的文章感兴趣, 这里有我的一些 数据可视化, D3.js 方面的文章, 欢迎 fork && star: https://github.com/ssthouse/s... ...

June 1, 2019 · 1 min · jiezi

gitbash自定义编辑器在命令行打开编辑以及命令行打开当前目录

写代码的过程中,偶尔会遇到在git-bash里头提交时最后一次检查代码的修改记录万一想改动每次都是alt+tab或者win+tab(原谅我是个win狗~)切换到编辑器修改了再切换回来进行提交so~一、命令行打开默认编辑器进行选中文件编辑 首先要自定义命令,在桌面上新建一个文件,文件名就是你想敲的执行命令(比如我,想用notpad打开),文件里头写入: #!/bin/sh"D:Notpad++\notpad++.exe" $1 &注:查了一下,最后的 & 符号表示在后台打开 注意下图我放置的位置 好,下面试试效果: 恩,nice!下次只需要敲这个命令,修改了之后保存叉掉文件就行了 二、打开当前目录的文件夹这个没什么说的,没错,就是这么简单 start .

April 25, 2019 · 1 min · jiezi

手把手带你撸一个cli工具

你有没有遇到过在没有vue-cli、create-react-app这样子的脚手架的时候一个文件一个文件的去拷贝老项目的配置文件。最近,笔者就在为组里的框架去做一套基本的cli工具。通过这边文章,笔者希望大家都能简单的去实现一个属于自己的脚手架工具。原文链接: https://juejin.im/user/57ac15…做好准备工作首先,我们需要去新建一个项目并初始化package.jsonmkdir my-cli && cd my-clinpm init然后我们需要在项目中新建bin文件夹,并将package.json中提供一个bin字段并指向我们的bin文件夹下,这样通过npm我们就可以实现指令的软链了。“bin”: { “mycli”: “bin/mycli”},在mycli中,我们要在头部增加这样一句注释,作用是"指定由哪个解释器来执行脚本"。#!/usr/bin/env nodeconsole.log(‘hello world’);接下来,全局安装我们这个包,这样我们就可以直接在本地使用mycli这个指令了。sudo npm install -g提供基本模版既然我们要去做一个初始化项目的cli,那么项目模版就必不可少了,笔者在这里提前准备了一个demo的项目目录模版,这里就不展开赘述了。编写逻辑其实核心逻辑很简单,就是通过控制台获取到用户的一些自定义选项,然后根据选项去从本地或者远程仓库拿到我们提前准备好的模版,将配置写入模版并最后拷贝模版到本地就行了。我们在src下新增creator.js文件,这个文件导出一个Creator的类。在这个类中现在仅需要三个简单的方法:init用于初始化、ask用于和命令行交互获取用户选择输入的数据、write用于调用模版的构建方法去执行拷贝文件写数据的任务。class Creator { constructor() { // 存储命令行获取的数据,作为demo这里只要这两个; this.options = { name: ‘’, description: ‘’, }; } // 初始化; init() {} // 和命令行交互; ask() {} // 拷贝&写数据; write() {}}module.exports = Creator;先去完善init方法,这个方法里我们仅需要调用ask方法和命令行交互并做一些提示即可(可以通过chalk这个库去丰富我们的命令行交互色彩)// …init() { console.log(chalk.green(‘my cli 开始’)); console.log(); this.ask();}// …接下来是ask方法,在这个方法中,我们需要根据提示引导用户输入问题并获取用户的输入,这里用到inquirer这个库来和命令行交互。// …ask() { // 问题 const prompt = []; prompt.push({ type: ‘input’, name: ’name’, message: ‘请输入项目名称’, validate(input) { if (!input) { return ‘请输入项目名称!’; } if (fs.existsSync(input)) { return ‘项目名已重复!’ } return true; } }); prompt.push({ type: ‘input’, name: ‘description’, message: ‘请输入项目描述’, }); // 返回promise return inquirer.prompt(prompt);}// …修改刚才的init方法,将ask方法改为Promise调用。init() { console.log(chalk.green(‘my cli 开始’)); console.log(); this.ask().then((answers) => { this.options = Object.assign({}, this.options, answers); console.log(this.options); });}现在我们去命令行试一下,修改bin/mycli文件,然后去运行mycli命令。#!/usr/bin/env nodeconst Creator = require(’../src/creator.js’);const project = new Creator();project.init();在和用户交互完毕并获取到数据后,我们要做的就是去调用write方法执行拷贝构建了。考虑到日后可能增加很多的模版目录,不妨我们将每一类的模版拷贝构建工作放到模版中的脚本去做,从而增大可扩展性,新增template/index.js文件。接下来首先根据项目目录结构创建文件夹(注意区分项目的执行目录和项目目录的关系)。module.exports = function(creator, options, callback) { const { name, description } = options; // 获取当前命令的执行目录,注意和项目目录区分 const cwd = process.cwd(); // 项目目录 const projectPath = path.join(cwd, name); const buildPath = path.join(projectPath, ‘build’); const pagePath = path.join(projectPath, ‘page’); const srcPath = path.join(projectPath, ‘src’); // 新建项目目录 // 同步创建目录,以免文件目录不对齐 fs.mkdirSync(projectPath); fs.mkdirSync(buildPath); fs.mkdirSync(pagePath); fs.mkdirSync(srcPath); callback();}然后回到creator.js文件,在Creator中的write调用这个方法。// …init() { console.log(chalk.green(‘my cli 开始’)); console.log(); this.ask().then((answers) => { this.options = Object.assign({}, this.options, answers); this.write(); });}// …write() { console.log(chalk.green(‘my cli 构建开始’)); const tplBuilder = require(’../template/index.js’); tplBuilder(this, this.options, () => { console.log(chalk.green(‘my cli 构建完成’)); console.log(); console.log(chalk.grey(开始项目: cd ${this.options.name } &amp;&amp; npm install)); });}// …在开启文件拷贝写数据之前,我们需要用到两个库mem-fs和mem-fs-editor,前者可以帮助我们在内存中创建一个临时的文件store,后者可以以ejs的形式去编辑我们的文件。现在constructor中初始化store。constructor() { // 创建内存store const store = memFs.create(); this.fs = memFsEditor.create(store); this.options = { name: ‘’, description: ‘’, }; this.rootPath = path.resolve(__dirname, ‘../’); this.tplDirPath = path.join(this.rootPath, ’template’);}接下来在Creator中增加两个方法copy和copyTpl分别用于直接拷贝文件和拷贝文件并注入数据。getTplPath(file) { return path.join(this.tplDirPath, file);}copyTpl(file, to, data = {}) { const tplPath = this.getTplPath(file); this.fs.copyTpl(tplPath, to, data);}copy(file, to) { const tplPath = this.getTplPath(file); this.fs.copy(tplPath, to);}然后我们根据ejs的语法修改模版中的package.json文件以实现数据注入的功能{ “name”: “<%= name %>”, “version”: “1.0.0”, “description”: “<%= description %>”, “main”: “index.js”, “scripts”: {}, “author”: “”, “license”: “ISC”}回到template/index.js中,对模版中的文件进行相应的拷贝和数据注入操作,最后打印一些可视化的信息。module.exports = function(creator, options, callback) { const { name, description } = options; // 获取当前命令的执行目录,注意和项目目录区分 const cwd = process.cwd(); // 项目目录 const projectPath = path.join(cwd, name); const buildPath = path.join(projectPath, ‘build’); const pagePath = path.join(projectPath, ‘page’); const srcPath = path.join(projectPath, ‘src’); // 新建项目目录 // 同步创建目录,以免文件目录不对齐 fs.mkdirSync(projectPath); fs.mkdirSync(buildPath); fs.mkdirSync(pagePath); fs.mkdirSync(srcPath); creator.copyTpl(‘packagejson’, path.join(projectPath, ‘package.json’), { name, description, }); creator.copy(‘build/build.js’, path.join(buildPath, ‘build.js’)); creator.copy(‘page/index.html’, path.join(pagePath, ‘index.html’)); creator.copy(‘src/index.js’, path.join(srcPath, ‘index.js’)); creator.fs.commit(() => { console.log(); console.log(${chalk.grey(创建项目: ${name})} ${chalk.green('✔ ')}); console.log(${chalk.grey(创建目录: ${name}/build)} ${chalk.green('✔ ')}); console.log(${chalk.grey(创建目录: ${name}/page)} ${chalk.green('✔ ')}); console.log(${chalk.grey(创建目录: ${name}/src)} ${chalk.green('✔ ')}); console.log(${chalk.grey(创建文件: ${name}/build/build.js)} ${chalk.green('✔ ')}); console.log(${chalk.grey(创建文件: ${name}/page/index.html)} ${chalk.green('✔ ')}); console.log(${chalk.grey(创建文件: ${name}/src/index.js)} ${chalk.green('✔ ')}); callback(); });}执行mycli指令创建项目,一个简单的cli就完成了。结语到此,一个简单的cli就制作完成了,大家可以参考vue-cli、create-react-app等优秀的cli适当的扩展自己的cli工具。 ...

March 26, 2019 · 2 min · jiezi

汇编基本命令整理

今晚上汇编,因为下课很无聊所以老猪我抽空整理了一下汇编的基本命令,发上来给大家分享一下 ^ _ ^-r 查看、改变CPU寄存器的内容(1)查看CPU寄存器里面的内容-r (2)改变寄存器里面的内容-r axAX 0000:1111-rcs-rip-d 查看内存中的内容(1)查看指定内存位置中的内容查看内存10000H处的内容-d 1000:0-d 1000:0 f-e 改写内存中的内容(1)从内存10010的位置开始改写-e 1000:10(2)从内存10000位置开始写入数值1、字符"a"……-e 1000:0 1 ‘a’ 2 ‘b’ 3 ‘c’(3)向内存中写入字符串-e 1000:0 1 “a+b” 2 “c++” 3 “IBM”(4)将机器码写入内存中-e 1000:0 b8 01 00 b9 02 00 01 c8b80100 mov ax,0001b90200 mov cx,000201c8 add ax,cx-u 将命令翻译为汇编指令-u 1000:0-t 执行CS:IP指向的命令-a 以汇编命令的形式在内存中写入机器命令-a 1000:01000:0000 mov ax,11000:0003 mov bx,2

March 6, 2019 · 1 min · jiezi

优秀的命令行工具整理(三)

原作者:Darren Burns 授权 LeanCloud 翻译,作者:weakish@LeanCloud本文是「优秀的命令行工具」系列的第三篇。在这篇文章中,我将展示五个命令行工具,这些工具能助你更方便地解决常见问题。tig 交互式地浏览 git 仓库有了 tig,无需离开命令行,就能交互式地浏览 git 仓库。tig 的使用简单直观,提供了 stash、staging、log 等视图。感谢 Renato Suero [@renatosuero] 在 DEV 上向我推荐 tig。安装 tigmacOS (Homebrew): brew install tigPathPicker (fpp) 快速选择文件PathPicker 是由 Facebook 推出的命令行文件速选库。下面的动画摘自 PathPicker 文档。摘自PathPicker 官网:PathPicker 接受各种各样的输入 —— git 命令的输出,grep 结果,搜索 —— 几乎任何输入都支持。解析输入后,PathPicker 呈现出供你选择文件的美观界面。选中文件后,可以用你偏爱的编辑器打开,或执行任意命令。感谢 Nikolay Dubina (@nikolayid)推荐这一工具。安装 PathPickermacOS (Homebrew): brew install fpptldr 使用命令行工具的实用示例tldr 助你快速查看使用命令行工具的实际示例。简而言之,「tl;dr」版本的 man 页面。tldr 的例子由社区维护,存储于 tldr 的 GitHub 仓库。安装 tldr推荐使用 npm 安装:npm install -g tldrmacOS (Homebrew): brew install tldrgron 查看 JSONgron 将 JSON 文本转换为离散的赋值语句,以便查找。我特别喜欢组合 fzf 使用(我在本系列的第一篇文章中提到过这个工具),这样可以交互式地查看 API:gron 也可以用来转换 JSON 对象(例子)。不过这不是 gron 的主要使用场景,使用 [jq] 这样的专门工具解决这类任务大概更合适。安装 gronmacOS (Homebrew): brew install gronthefuck 快速修正命令行手误输入命令时拼错了,输入 fuck ,thefuck 会给出一些候选的正确命令。很不幸,这个命令的名称稍微有点黄暴,你也许想要起个别名。安装 thefuckmacOS (Homebrew): brew install thefuck额外福利:explainshell,解释命令如果你手头有一行很复杂的命令,想要了解它做了什么,又不想一个个查 man 或 tldr,那么你可以使用 explainshell:结语希望你对这篇文章中的工具感兴趣!想看更多类似内容,欢迎在 Twitter 和 DEV 上关注 @_darrenburns。 ...

January 23, 2019 · 1 min · jiezi

优秀的命令行工具整理(二)

原文作者: Darren Burns 翻译:weakish@LeanCloud原文链接:Power Up Your Command Line本文是「命令行威力提升」系列的第二篇,这一系列展示一些出色的非标准工具,这些工具能让命令行用起来更容易、更享受。peco 交互式过滤将任何命令的输出通过管道传给 peco,便能交互式地过滤输出,查找所需信息。你可以把它想成交互式 grep,随着输入实时更新结果,让搜索过程更直观。你可以使用上下键选择搜索结果,然后用回车键确认。按下回车后,peco 会输出结果。安装 pecomacOS (Homebrew): brew install pecohexyl 十六进制查看器检查二进制文件时通常查看文件的十六进制表示。hexyl 是个命令行下的十六进制查看器。界面分为三栏:偏移量 当前所在的字节数十六进制 文件的十六进制表示(自身又分为两栏,不过在上面的 gif 例子中不可见)表示 尝试将文件显示为文本(同样分为两栏,gif 例子中未显示)hexyl 显示的每个字节的颜色取决于其类型(NULL、ASCII、non-ASCII等),这很有助于可读性。小窍门 :查看二进制文件或大的文本文件时,输出经常会超出屏幕,所以你可以把 hexyl 的输出传给 bat 或 less,以支持分页。如果用 less,需要加上 –raw-control-chars/-r 参数以正确显示颜色。hexyl 由 David Peter 使用 Rust 编写,他也是 bat、fd、hyperfine 的作者,我在本系列的第一篇文章中介绍过这些工具。安装 hexylmacOS (Homebrew): brew install hexylpomo 番茄钟计时器番茄工作法是提升生产效率的好方法。如果你还没听说过,那么它大概是这样的:你心无旁骛地工作 25 分钟放松 5 分钟,做任何你想做的事情(只要不是工作 ????)重复以上步骤 4 次(根据需要调整这个数字),接着休息 15 分钟根据番茄工作法这一理论,遵循这一计划能让你在相对较短的时间内完成相对较多的事情。这也许不适用于每个人,但我个人验证了它的有效性!pomo 是一个简单的命令行工具,助你依照番茄工作法管理时间。安装 pomo在 macOS 上安装:从 GitHub 下载二进制文件:curl -L -o pomo https://github.com/kevinschoon/pomo/releases/download/0.6.0/pomo-0.6.0-darwin-amd64设置权限:chmod +x pomo加入 PATH:mv pomo /usr/local/bin初始化数据库:pomo initncdu 分析、清理磁盘空间如果你的计算机上有很多项目,最近也没有清理过磁盘。那么你几乎一定能找到一个占用大量磁盘的文件夹(我发现旧项目的 node_modules 文件夹特别容易占用大量空间)。ncdu是我最爱的修复工具。事实上,在创建下面的 ncdu 演示例子时,我清理了 10 GiB 的磁盘空间!只需运行 ncdu 即可使用。它会扫描当前目录下的所有子目录,所以如果在家目录运行 ncdu,也许需要较长时间扫描。ncdu 的 ncurses 界面可以使用方向键,也可以使用 vim 风格的快捷键。安装 ncdumacOS (Homebrew): brew install ncduHTTPie curl 的现代替代品HTTPie 是一个更简单(不像 curl,每次使用都要 Google 下用法)、功能更多、更美观的 curl 替代品,可以在命令行调用 HTTP 的 API。到目前为止,我介绍的工具中,它是最流行的,而且有很精良的文档。http 命令的输出足够与 cURL 区分开来。输出的 JSON 响应带语法高亮,十分美观,可读性要好很多。如果你偏爱图形 UI,那么你也许会喜欢 Insomnia、Postman 或 Paw (Paw 需要购买许可,并且只适用于 macOS)。安装 HTTPiemacOS (Homebrew): brew install httpie结语感谢阅读!在这一系列的下一篇文章中,还有一些工具值得一提。如果你有任何建议,欢迎联系我!如果你对更多类似内容感兴趣,可以在 Twitter 上关注我。 ...

January 18, 2019 · 1 min · jiezi

优秀的命令行工具整理 (一)

原文作者: Darren Burns 翻译:weakish@LeanCloud原文链接:https://url.leanapp.cn/darren我打算写一系列文章,展示下近些年发现的一些很棒的非标准命令行工具,这是第一篇。如果你用命令行,那么这些工具中大概至少有一个能让你的生活更舒心。z 跳转现代浏览器地址栏可以智能模糊搜索,节省了大量时间。想要刷下推特?只需在地址栏输入「tw」然后回车。相比之下,在命令行下使用 cd 访问文件系统,方式就太陈旧了。谢天谢地,z 给命令行带来了浏览器风格的导航。短暂的学习期之后,z 能让你从任意位置跳转到一个目录,只需输入目标目录名的子字符串。z 会跳转到哪个目录取决于你提供的字符串参数、访问目录的频繁程度、访问目录的最近时间。这称为「频近度 (frecency)」。z 不仅提高了速度,还降低了认知负担。使用 cd 时,你需要准确回忆目标目录在目录树的位置,并计算到达目录的路径。有了 z,只需知道目录的名称。z 也已经移植到了其他 shell (例如 fish 和 zsh)。类似的项目有 autojump。安装 z在 macOS 上使用 Homebrew 安装 bash版本:brew install z在 macOS 上使用 Fisher 安装fish 版本:fisher add jethrokuan/zfzf 快速模糊搜寻器安装 [fzf] (https://git.io/C4FBDw) 后,在命令行的任何地方按下 Ctrl + T,就可以开启交互式模糊搜索界面,递归搜索当前目录下的文件。输入搜索项后,上、下键选择结果,回车上屏:在上面的例子中,我输入了 bat(还可以是其他任何命令,例如 less、cd 等),接着按下 Ctrl + T。接着输入 five,回车,插入路径 src/five.rs 至光标所在处,而不必先输入 src,再按 tab 键,再输入 fi,再按 tab 键——路径很长或者不好记的时候,这样很麻烦。安装 fzfmacOS (Homebrew): brew install fzffish 绑定: fisher add jethrokuan/fzfbat 带语法高亮的文件查看bat 助你快速查看文件,有语法高亮。bat 可以无缝替换 cat。如果输出过大(如上面的例子所示),bat 会将输出传给 less,自动分页。安装 batmacOS (Homebrew): brew install batbench 代码性能测试[bench] (https://git.io/fhZwU) 是极为有用的测试代码性能的工具。它是用 Haskell 写的,从这点上说,算是这篇文章中最酷的。任何可以在终端中运行的命令都可以传给它(加引号),bench 会重复运行该命令,测量执行时间。测试完成后,bench 会输出有用的统计数据。衡量代码执行时间,相比系统内置的 time 命令,bench 更为强大。类似的工具有 hyperfine ,是用 Rust 编写的。安装 benchmacOS (Homebrew): brew install benchasciinema 和 svg-term录制终端为 SVG 动画这篇文章中的终端剪辑实际上是 SVG 动画!使用 SVG 而不是视频文件有不小的优势:任意缩放 ????可以像其他图像一样嵌入 Markdown 文件 ????文件较小 ????SVG 动画比视频酷太多 ????我使用 [asciinema] (https://asciinema.org/) 录制终端。输入 asciinema rec 即可开始录制。完成后按 Ctrl+D,选择本地保存或上传 asciinema.orgsvg-term 可以根据 asciinema 录制文件生成 SVG 动画。如果你将录制文件上传到了 asciinema,需要访问 asciinema 链接将其设为公开。转换录制文件为 SVG 动画,需要提供录制 ID (公开 asciinema 页面后可以在 URL 中找到 ID),输出文件名,还有其他一些可选参数。例如,我使用如下命令将上面例子中的终端录制 (https://asciinema.org/a/219486) 转换为 SVG 文件:svg-term –cast=219486 –out ~/somewhere/out.svg –padding 18 –height 8 –width 80或者,如果你不想把录制文件上传到 asciinema,你也可以直接使用 svg-term 转换本地录制文件(感谢 svg-term-cli 的作者 Mario Nebl 指出这一点):asciinema rec cast.jsoncat cast.json | svg-term-cli安装 asciinema 和 svg-term在 macOS 上安装 asciinema:brew install asciinema在 macOS 上安装 svg-term: npm install -g svg-term-cliwrk 测试 HTTP API 性能[wrk] (https://github.com/wg/wrk) 是个方便的小工具,可以测试 API 性能。为了演示它的用法,我在本地的 8001 端口运行了一个最小化的 Python HTTP API 服务器,它只有一个端点(/hello)。用 wrk 测试它的性能(5 秒内,使用 12 个线程发起 200 个连接):调整线程数、连接数、时长可以测试不同负载下 API 的表现。它不能代替 Locust 和 JMeter 这样的性能测试工具,但很轻量,在许多场景下够用。很不幸,基于 wrk 的命令行接口发起 POST 请求很笨拙:需要用 Lua 编写一个小脚本,作为参数传给命令(详见文档)。安装 wrkmacOS (Homebrew): brew install wrkexa 替代 lsexa 是 ls 的现代替代品,其彩色输出更为易读,并提供了更多控制输出如何呈现的选项。加上 –git-ignore 参数会根据 .gitignore 忽略对应文件,使用 -T 参数则能以树型结构列出目录。安装 examacOS (Homebrew): brew install exafd 查找文件和目录通常使用 find 命令基于正则表达式查找文件或目录。fd 是用 Rust 编写的 find 替代品。使用合理的默认值,提供更方便的界面,速度也更快。fd 遵循 .gitignore 文件,也支持并行命令执行。并行命令执行可以在搜索返回的每个文件和目录上(并行)执行命令。fd 文档中的一个例子是找出所有 .jpg 文件,并行转换为 .png 文件(使用 convert 命令):fd -e jpg -x convert {} {.}.png安装 fdmacOS (Homebrew): brew install fdrg (ripgrep) 查找文件中的字符串rg 是 grep 的替代品,它比 grep 快很多。rg 是用 Rust 编写的,VS Code 编辑器的搜索功能其实是通过调用 rg 实现的。在性能评测中,rg 一贯超过类似工具。安装 ripgrepmacOS (Homebrew): brew install ripgrep结语我希望你在这篇文章中发现了有用的工具!我打算让这篇文章成为及时更新的工具库,收罗有用的替代性命令行工具,所以我可能会时不时更新这篇文章。如果你对更多类似内容感兴趣,欢迎在 Twitter 上关注我。 ...

January 16, 2019 · 2 min · jiezi

Scrapy-实用的命令行工具实现方法

其实这篇文章是scrapy源码学习的(一),加载器那篇才是(二)scrapy的命令行工具本文环境:wind7 64bitspython 3.7scrapy 1.5.1scrapy拥有非常灵活的低耦合的命令行工具,如果自己想要重新实现覆盖掉scrapy自带的命令也是可以的。使用它的命令行工具可以大致分为两种情况:在创建的project路径下不在project路径下先看下不在scrapy项目路径下的命令行有哪些:Scrapy 1.5.1 - no active projectUsage: scrapy <command> [options] [args]Available commands: bench Run quick benchmark test fetch Fetch a URL using the Scrapy downloader genspider Generate new spider using pre-defined templates runspider Run a self-contained spider (without creating a project) settings Get settings values shell Interactive scraping console startproject Create new project version Print Scrapy version view Open URL in browser, as seen by Scrapy [ more ] More commands available when run from project directoryUse “scrapy <command> -h” to see more info about a command在项目路径下的命令行新增了check、crawl、edit、list、parse这些命令,具体:Scrapy 1.5.1 - project: myspider01Usage: scrapy <command> [options] [args]Available commands: bench Run quick benchmark test check Check spider contracts crawl Run a spider edit Edit spider fetch Fetch a URL using the Scrapy downloader genspider Generate new spider using pre-defined templates list List available spiders parse Parse URL (using its spider) and print the results runspider Run a self-contained spider (without creating a project) settings Get settings values shell Interactive scraping console startproject Create new project version Print Scrapy version view Open URL in browser, as seen by ScrapyUse “scrapy <command> -h” to see more info about a command也即是说scrapy可以根据当前路径是否是scrapy项目路径来判断提供可用的命令给用户。创建一个scrapy项目在当前路径下创建一个scrapy项目,DOS下输入:scrapy startproject myproject可以查看刚刚创建的项目myproject的目录结构:├── scrapy.cfg //scrapy项目配置文件├── myproject ├── spiders // 爬虫脚本目录 ├── init.py ├── init.py ├── items.py ├── middlewares.py ├── pipelines.py ├── settings.py // 项目设置 可以断定,在我们使用"startproject"这个scrapy命令时,scrapy会把一些项目默认模板拷贝到我们创建项目的路径下,从而生成我们看到的类似上面的目录结构。我们可以打开scrapy的包,看看这些模板在哪个地方。切换至scrapy的安装路径(比如:..Python37Libsite-packagesscrapy),可以看到路径下有templates文件夹,而此文件夹下的project文件夹便是创建项目时拷贝的默认模板存放目录。那么scrapy是怎么实现类似“startproject”这样的命令的呢?打开scrapy源码找到入口scrapy是使用命令行来启动脚本的(当然也可以调用入口函数来启动),查看其命令行实现流程必须先找到命令行实行的入口点,这个从其安装文件setup.py中找到。打开setup.py 找到entry_points:… entry_points={ ‘console_scripts’: [‘scrapy = scrapy.cmdline:execute’] },…可以看到scrapy开头的命令皆由模块scrapy.cmdline的execute函数作为入口函数。分析入口函数先浏览一下execute函数源码,这里只贴主要部分:def execute(argv=None, settings=None): if argv is None: argv = sys.argv … #主要部分:获取当前项目的设置 if settings is None: settings = get_project_settings() # set EDITOR from environment if available try: editor = os.environ[‘EDITOR’] except KeyError: pass else: settings[‘EDITOR’] = editor #检查提醒已不被支持的设置项目 check_deprecated_settings(settings) … #主要部分:判断是否在项目路径下,加载可见命令,解析命令参数 inproject = inside_project() cmds = _get_commands_dict(settings, inproject) cmdname = _pop_command_name(argv) parser = optparse.OptionParser(formatter=optparse.TitledHelpFormatter(), \ conflict_handler=‘resolve’) if not cmdname: _print_commands(settings, inproject) sys.exit(0) elif cmdname not in cmds: _print_unknown_command(settings, cmdname, inproject) sys.exit(2) cmd = cmds[cmdname] parser.usage = “scrapy %s %s” % (cmdname, cmd.syntax()) parser.description = cmd.long_desc() settings.setdict(cmd.default_settings, priority=‘command’) cmd.settings = settings cmd.add_options(parser) opts, args = parser.parse_args(args=argv[1:]) _run_print_help(parser, cmd.process_options, args, opts) cmd.crawler_process = CrawlerProcess(settings) _run_print_help(parser, _run_command, cmd, args, opts) sys.exit(cmd.exitcode)阅读cmdline.py的execute函数,大概了解了命令行实现的基本流程:1.获取命令参数命令参数的获取可以通过两种方式传递:第一种是调用execute,比如:from scrapy.cmdline import executeexecute(argv=[‘scrapy’,‘startproject’,‘myproject’,’-a’,‘xxxx’])这样就相当于第二种方式:命令控制台执行scrapy startproject myproject -a xxxx传递的参数都是[‘scrapy’,‘startproject’,‘myproject’,’-a’,‘xxxx’]2.获取scrapy项目配置如果当前不是调用的方式传递settings给execute入口,而是一般的命令控制台启动scrapy,那么scrapy会在当前路径下搜索加载可能存在的项目配置文件。主要是通过函数get_project_settings执行。ENVVAR = ‘SCRAPY_SETTINGS_MODULE’def get_project_settings(): #获取配置 if ENVVAR not in os.environ: #初始化获取项目的default级配置,即是scrapy生成的默认配置 project = os.environ.get(‘SCRAPY_PROJECT’, ‘default’) #初始化项目环境,设置系统环境变量SCRAPY_SETTINGS_MODULE的值为配置模块路径 init_env(project) settings = Settings() settings_module_path = os.environ.get(ENVVAR) if settings_module_path: settings.setmodule(settings_module_path, priority=‘project’) … return settings获取的配置文件主要是scrapy.cfg,我们可以看下他的内容:[settings]default = myproject.settings[deploy]#url = http://localhost:6800/project = myproject在生成项目myproject的时候,这个配置文件就已经指定了项目设置模块的路径"myproject.settings",所以上面的get_project_settings函数获取便是配置文件settings字段中的default键值,然后导入该设置模块来生成配置。具体实现在init_env函数中。def init_env(project=‘default’, set_syspath=True): “““在当前项目路径下初始化项目环境. 并且通过配置系统环境来让python能够定位配置模块 "”” #在项目路径下进入命令行,才能准确获取配置 #获取可能存在scrapy.cfg配置文件的模块路径 cfg = get_config() #获取到配置文件后设置系统环境变量SCRAPY_SETTINGS_MODULE为配置模块路径, #如: myproject.settings,默认项目级别均为default,即是配置文件字段settings中的键 if cfg.has_option(‘settings’, project): os.environ[‘SCRAPY_SETTINGS_MODULE’] = cfg.get(‘settings’, project) #将最近的scrapy.cfg模块路径放入系统路径使Python能够找到该模块导入 closest = closest_scrapy_cfg() if closest: projdir = os.path.dirname(closest) if set_syspath and projdir not in sys.path: #加入项目设置模块路径到系统路径让Python能够定位到 sys.path.append(projdir)def get_config(use_closest=True): "”" SafeConfigParser.read(filenames) 尝试解析文件列表,如果解析成功返回文件列表。如果filenames是string或Unicode string, 将会按单个文件来解析。如果在filenames中的文件不能打开,该文件将被忽略。这样设计的目的是, 让你能指定本地有可能是配置文件的列表(例如,当前文件夹,用户的根目录,及一些全系统目录), 所以在列表中存在的配置文件都会被读取。""" sources = get_sources(use_closest) cfg = SafeConfigParser() cfg.read(sources) return cfgdef get_sources(use_closest=True): ‘‘‘先获取用户的根目录,及一些全系统目录下的有scrapy.cfg的路径加入sources 最后如果使用最靠近当前路径的scrapy.cfg的标志use_closest为True时加入该scrapy.cfg路径’’’ xdg_config_home = os.environ.get(‘XDG_CONFIG_HOME’) or \ os.path.expanduser(’/.config’) sources = [’/etc/scrapy.cfg’, r’c:\scrapy\scrapy.cfg’, xdg_config_home + ‘/scrapy.cfg’, os.path.expanduser(’/.scrapy.cfg’)] if use_closest: sources.append(closest_scrapy_cfg()) return sourcesdef closest_scrapy_cfg(path=’.’, prevpath=None): """ 搜索最靠近当前当前路径的scrapy.cfg配置文件并返回其路径。 搜索会按照当前路径–>父路径的递归方式进行,到达顶层没有结果则返回‘’ """ if path == prevpath: return ’’ path = os.path.abspath(path) cfgfile = os.path.join(path, ‘scrapy.cfg’) if os.path.exists(cfgfile): return cfgfile return closest_scrapy_cfg(os.path.dirname(path), path)通过init_env来设置os.environ[‘SCRAPY_SETTINGS_MODULE’]的值,这样的话#将项目配置模块路径设置进系统环境变量os.environ[‘SCRAPY_SETTINGS_MODULE’] = ‘myproject.settings’初始化后返回到原先的get_project_settings,生成一个设置类Settings实例,然后再将设置模块加载进实例中完成项目配置的获取这一动作。3.判断是否在scrapy项目路径下判断当前路径是否是scrapy项目路径,其实很简单,因为前面已经初始化过settings,如果在项目路径下,那么os.environ[‘SCRAPY_SETTINGS_MODULE’]的值就已经被设置了,现在只需要判断这个值是否存在便可以判断是否在项目路径下。具体实现在inside_project函数中实现:def inside_project(): scrapy_module = os.environ.get(‘SCRAPY_SETTINGS_MODULE’) if scrapy_module is not None: try: import_module(scrapy_module) except ImportError as exc: warnings.warn(“Cannot import scrapy settings module %s: %s” % (scrapy_module, exc)) else: return True return bool(closest_scrapy_cfg())4.获取命令集合,命令解析知道了当前是否在项目路径下,还有初始化了项目配置,这个时候就可以获取到在当前路径下能够使用的命令行有哪些了。获取当前可用命令集合比较简单,直接加载模块scrapy.commands下的所有命令行类,判断是否需要在项目路径下才能使用该命令,是的话直接实例化加入一个字典(格式:<命令名称>:<命令实例>)返回,具体实现通过_get_commands_dict:def _get_commands_dict(settings, inproject): cmds = _get_commands_from_module(‘scrapy.commands’, inproject) cmds.update(_get_commands_from_entry_points(inproject)) #如果有新的命令行模块在配置中设置,会自动载入 cmds_module = settings[‘COMMANDS_MODULE’] if cmds_module: cmds.update(_get_commands_from_module(cmds_module, inproject)) return cmdsdef _get_commands_from_module(module, inproject): d = {} for cmd in _iter_command_classes(module): #判断是否需要先创建一个项目才能使用该命令, #即目前是否位于项目路径下(inproject)的可用命令有哪些,不是的有哪些 if inproject or not cmd.requires_project: cmdname = cmd.module.split(’.’)[-1] #获取该命令名称并实例化 加入返回字典 #返回{<命令名称>:<命令实例>} d[cmdname] = cmd() return d def _iter_command_classes(module_name): #获取scrapy.commands下所有模块文件中属于ScrapyCommand子类的命令行类 for module in walk_modules(module_name): for obj in vars(module).values(): if inspect.isclass(obj) and \ issubclass(obj, ScrapyCommand) and \ obj.module == module.name and \ not obj == ScrapyCommand: yield obj其中判断是否是命令类的关键在于该命令模块中的命令类是否继承了命令基类ScrapyCommand,只要继承了该基类就可以被检测到。这有点类似接口的作用,ScrapyCommand基类其实就是一个标识类(该类比较简单,可以查看基类代码)。而该基类中有一个requires_project标识,标识是否需要在scrapy项目路径下才能使用该命令,判断该值就可以获得当前可用命令。获取到了可用命令集合,接下来会加载Python自带的命令行解析模块optparser.OptionParser的命令行参数解析器,通过实例化获取该parser,传入当前命令实例的add_options属性方法中来加载当前命令实例附加的解析命令,如:-a xxx, -p xxx, –dir xxx 之类的类似Unix命令行的命令。这些都是通过parser来实现解析。5.判断当前命令是否可用其实在加载解析器之前,会去判断当前的用户输入命令是否是合法的,是不是可用的,如果可用会接下去解析执行该命令,不可用便打印出相关的帮助提示。比如:Usage===== scrapy startproject <project_name> [project_dir]Create new projectOptions=======–help, -h show this help message and exitGlobal Options—————-logfile=FILE log file. if omitted stderr will be used–loglevel=LEVEL, -L LEVEL log level (default: DEBUG)–nolog disable logging completely–profile=FILE write python cProfile stats to FILE–pidfile=FILE write process ID to FILE–set=NAME=VALUE, -s NAME=VALUE set/override setting (may be repeated)–pdb enable pdb on failure至此,scrapy命令行工具的实现流程基本结束。学习点scrapy的命令行工具实现了低耦合,需要删减增加哪个命令行只需要在scrapy.commands模块中修改增删就可以实现。但是实现的关键在于该模块下的每一个命令行类都得继承ScrapyCommand这个基类,这样在导入的时候才能有所判断,所以我说ScrapyCommand是个标识类。基于标识类来实现模块的低耦合。下一篇将会记录根据借鉴scrapy命令行工具实现方法来实现自己的命令行 ...

November 21, 2018 · 3 min · jiezi

WSL 配置指北:打造 Windows 最强命令行

原文发表在我的 博客 上,欢迎订阅。;)在两年前的八月,Microsoft 正式发布了 Windows 10 Anniversary Update 周年更新(它还有着 RS1,Version 1607,Build 14393 等一大堆别名)。其中最让包括我在内的众多开发者感到兴奋的特性之一,就是 WSL(Windows Subsystem for Linux,当时还叫 Bash on Ubuntu on Windows)的正式加入。在 Windows 上原生运行 Linux 可执行文件,牛逼疯了!然而 Bug10 也不是浪得虚名,原本只提供给 Insider 的 WSL 在正式发布后依然问题多多(不仅 zsh、tmux 等工具无法使用,网络相关的操作更是一概欠奉,还有各种各样 奇妙的 BUG),基本没有可用性,我在尝鲜了一段时间后也不得不重回 Cygwin 的怀抱。不过好消息是,在之后的更新中,这些 BUG 都已被逐一消灭。经过了两年的发展,WSL 已经足够成熟,我也是时候完成这篇一咕再咕的博文了。1. 我理想中的命令行界面既然违反广告法取了这么个标题,那我自然得先描述一下我的目标,也就是我理想中的命令行界面应该是什么样子的(如果你不清楚命令行的概念,可以看看我之前写的 这篇文章):好看(配色、字体可以自由设定);支持 UTF-8 字符的输入与显示;支持常见的 NIX 命令行工具(cat、grep、awk 等);自动补全、语法高亮、历史记录;完善的复制粘贴支持;互操作性(共享文件系统、网络栈,可调用 Win32 程序);支持常用的脚本语言(PHP、Python、Node.js 等);包管理器,以及其他各种常用软件的支持;快速呼出(快捷键、右键菜单入口)。然而遗憾的是,Windows 上的命令行一直以来都很微妙。2. 难用的 Windows 命令行停停停,那边的 PowerShell 爱好者 ,咱别动粗成吗?首先我要对标题做出一些订正,Windows 原生命令行其实也可以不那么难用。虽然 cmd.exe 是公认的难用到反人类(毕竟是用来兼容 DOS 的老古董),但后来推出的 PowerShell 已经足够强大且现代化,能够称得上是一个成熟的命令行 Shell 了。如果你愿意学习的话,PowerShell 几乎可以满足你对命令行的所有期待。这一点可以参见:Is PowerShell ready to replace my Cygwin shell on Windows?但是,PowerShell 与 Bash 等类 Unix 系统上的 Shell 程序几乎是两个完全不同的世界。不仅语法不同,其平台上各类常用的命令行工具也基本不一致(比如类 Unix 系统中的 grep 对应 PowerShell 中的 Select-String,uniq 对应 Select-Object -Unique 等)。往深了说,他们的系统设计理念都是不一样的,比如很多人推崇的 Unix 哲学,在 Windows 上就基本不见踪影;而 COM 等概念也是 Windows 独一份。▲ 图片来源:シス管系女子 BEGINS 特別編 まんがでわかる WSL当然,我无意在此挑起操作系统间的圣战。Windows 和类 Unix 系统中的命令行哪个好用,见仁见智。不过对于包括我在内的很多用户都认为 Windows 命令行不怎么好用,仅此而已。回到正题。虽然 Windows 的命令行一直遭人诟病,但是人家的图形界面牛逼啊。于是无数工程师前赴后继,试图在 Windows 上创造出不输给类 Unix 系统的命令行体验 —— 却绝大多数以失败告终。曾经努力过的人,或者回到可爱的 Linux 上,或者进入高贵冷艳的 macOS 的世界。其中有先辈留下了 Cygwin、GnuWin32 等工具集,让我们可以在 Windows 下使用类 Unix 系统中常见的命令行工具,成为了不少 Windows 用户的救赎。然而,就当大家都觉得「也就这样了」的时候,Microsoft 出人意料地站了出来。带着他新鲜出炉的 WSL。3. Windows Subsystem for Linux,参上!大家都把 WSL 吹得这么牛逼,那 WSL 究竟是个什么玩意儿呢?简单来说,WSL 是一个 兼容层,有点像反过来的 Wine。首先,我问个问题,为什么 Linux 上的程序无法在 Windows 上运行呢?了解过一点操作系统原理的同学应该都知道,这是 Windows 与 Linux 的内核提供的接口不同(系统调用、API 等)导致的。举个栗子,我们想知道某目录下的内容,在 Linux 下我们会使用 ls 命令,而在 Windows 下我们会使用 dir 命令。当我们在 Linux 上执行 ls 命令,ls 会调用 getdents 这个系统调用,Linux 内核收到请求,将目录的内容返回给应用程序;当我们在 Windows 上执行 dir 命令,dir 会调用 NtQueryDirectoryFile 这个 API,NT 内核收到请求,将目录的内容返回给应用程序。虽然系统不同,但基本上都是一个道理。然而,当我们把 Linux 上的应用程序拿到 Windows 上运行时,应用程序和内核就双双懵逼了。比如 ls 会尝试调用 getdents 系统调用(理想化的情况下,暂不考虑可执行文件格式等问题),Windows 的 NT 内核一看,心说:「这他娘的什么东西,老子不认识啊,啥情况啊」,ls 也想:「尼玛,内核怎么不回话啊,咋回事儿啊」……两边语言不通,应用程序自然无法正确执行。但是有了 WSL,情况就不一样了。依然拿 ls 举例,当我们在 WSL 中运行 ls 命令时,ls 会调用 getdents 系统调用(这个系统调用接口是 WSL 提供的,Windows 本身并没有这个接口),WSL 收到这个请求,明白了应用程序是想要知道目录的内容,于是把 Linux 的系统调用转换为 NT API NtQueryDirectoryFile。NT 内核收到 WSL 的请求,将目录的内容返回给 WSL,WSL 再把返回的内容包装好后返回给 ls。也就是说,WSL 在 Linux 应用程序与 Windows NT 内核之间起到了翻译者的作用。很简单的道理,既然 NT 内核无法理解 Linux 应用程序的 POSIX 系统调用,那就弄个翻译来将 POSIX 系统调用实时转换为 NT 内核能理解的 API 调用,突出一个见人说人话、见鬼说鬼话。只要实现了足够多的系统调用翻译,那么理论上 WSL 可以完全模拟成一个 Linux 内核。相信各位都听说过鼎鼎大名的 Cygwin。同样是能让 Linux 应用程序运行在 Windows 上,WSL 和 Cygwin 有什么不同呢?其实差别还是挺大的。虽然 Cygwin 提供了完整的 POSIX 系统调用 API(以运行库 Cygwin.dll 的形式提供),但其依然工作在 User Mode;而 WSL 中的 Linux 应用程序进程会被包裹在一个叫做 Pico Process 的东西里,这个东西里发出的所有系统调用请求都会被直接送往 Kernel Mode 中的 lxcore.sys 与 lxss.sys 处理。同样是将 POSIX 系统调用转换为 Windows 中的 API,Cygwin 是转换成 Win32 API 的调用(因为它架设在 Win32 子系统上,很多内核操作受限于 Win32 的实现,比如 fork),而 WSL 则是转换为更底层的 NT API 调用(WSL 是与 Win32 平行的子系统,直接架设在 NT 内核上,可以通过 NT API 原生实现 fork 等系统调用)。▲ WSL 架构示意图。图片来源:Windows for Linux Nerds最重要的一点:如果使用 Cygwin,Linux 应用程序的源码必须 link 至 Cygwin 运行库(Cygwin*.dll),修改源码重新编译后才能在 Windows 下运行。这些重新编译后的 Linux 应用程序在调用 POSIX API 时不会直接去请求内核,而是会去调用 Cygwin 运行库,由运行库翻译成 Win32 API、执行调用后返回结果。这也就意味着,重新编译后的应用程序需要依赖 Cygwin 运行库才能正常运行(有时候你会碰到的「缺少 Cygwin1.dll」报错就是这个原因),而且这样编译出来的可执行程序是纯正的 Win32 PE 格式封装,只能在 Windows 上运行。而在 WSL 下,我们可以直接运行未经任何修改的 ELF 格式 Linux 可执行程序。▲ Cygwin 目录下,被编译成 Win32 可执行程序的 Linux 应用程序们。最后总结一波:WSL 就像是一个翻译官,就算那些未经修改的 Linux 应用程序们操着一口纯正的 POSIX 系统调用语法,WSL 也能快速准确地将其翻译为 NT 内核能听懂的 API 调用;而那些使用了 Cygwin 重新编译后的 Linux 应用程序,就像是改造人一样变成了 Win32 应用程序的形状,还被套了个翻译机。程序自己(源码中)说的是 POSIX,经过翻译机(Cygwin 运行库)之后就变成 Win32 API 调用了,这样 NT 内核也能听得懂。但是每次添加新程序都要改造,多麻烦啊,还是 WSL 原生态更健康(笑)。以上只是我对 WSL 的粗浅解释,其具体实现原理可以参考官方博客上的 这一系列文章。4. 安装 WSL,拥抱可爱的 Linux好了不说废话,让我们开始安装 WSL。注意,WSL 仅支持 64 位系统,且本文中所描述的安装方法仅适用于 Windows 10 Fall Creators Update(秋季创意者更新,RS3,Version 1709,Build 16299)及以上版本。第一步,打开「控制面板」中的「程序与功能」,点击左侧边栏的「启用或关闭 Windows 功能」选项,在弹出的窗口中勾选「适用于 Linux 的 Windows 子系统」,然后点击确定(可能需要重启)。如果你懒得用 GUI,也可以直接在 PowerShell 中以管理员权限执行命令:Enable-WindowsOptionalFeature -Online -FeatureName Microsoft-Windows-Subsystem-Linux第二步,打开 Microsoft Store,搜索「WSL」。挑选一个你喜欢的 Linux 发行版,然后点击安装。(截至目前,商店中可用的发行版有 Ubuntu、openSUSE、SUSE Linux Enterprise Server、Debian 以及 Kali Linux。)第三步,在开始菜单中找到你刚刚安装的发行版,打开它。等待几分钟的初始化过程,设定好用户名与密码后(不需要与 Windows 的相同,用过 Linux 的选手应该都懂的)就会自动进入 Linux 环境。至此,你已经完成了 WSL 的安装。你也可以同时安装多个发行版,它们的数据都是独立的,互不影响。5. 使用更专业的终端模拟器我猜你现在正在对上面那个窗口发呆。—— 这个新宋体他娘的是个什么情况?如果你正在使用中文 Windows 系统,而且之前并没有修改过 Win32 Console 的默认配置,那么你的 WSL 终端默认就会是这样的。新宋体,就是这么 Hardcore。惊不惊喜,意不意外?好吧不开玩笑,Windows 这个控制台窗口就是很多人讨厌它的原因之一,难用又难看。丑这一点倒还有解决方法(经过一番设置后还算能看,我以前就写过一篇关于 自定义 Windows 控制台字体 的文章),难用却是实打实的。尽管 Win10 上的控制台已经改进了不少(可以看看 Microsoft 的官方博客:Windows Command Line Tools For Developers),但其依然是最难用的终端模拟器之一,或许没有之一。因此,为了实现我们的目标,一个更强大的终端模拟器是必须的。终端模拟器是什么?为了这个回答这个问题,我专门写了一篇文章,去看看吧。:P我个人比较推荐的终端模拟器有:wsl-terminal专门为 WSL 开发的终端模拟器,基于 mintty 与 wslbridge,稳定易用。ConEmuWindows 上的老牌终端模拟器,功能极为强大,要啥有啥。Hyper基于 Electron 的跨平台终端模拟器,好看和可扩展性是卖点,BUG 不少。还有其他各种各样的终端模拟器,选个自己喜欢的就好。反正不管选哪个,都比默认的那玩意儿要好用。????另外,设定终端模拟器的 Shell 入口时有个坑,需要注意一下(参见下文 6.4)。▲ 我正在使用的终端,wsl-terminal 与 Hyper。好看是第一生产力。6. 让我们更深入一些以下是 WSL 的一些优化技巧。6.1 使用软件源镜像由于众所周知的原因,各大发行版默认的软件源在中国大陆的访问速度都很屎。我目前使用的是 清华大学的 Ubuntu 镜像源。6.2 安装 zsh 与 oh-my-zsh想要快乐地使用命令行,一个趁手的 Shell 是必不可少的。我个人习惯使用 zsh,安装步骤不再赘述。我的自定义 oh-my-zsh 主题:# ~/.oh-my-zsh/custom/themes/robbyrussell-ascii.zsh-theme# Modified from robbyrussell, the default theme of oh-my-zsh.# > blog git:(source) x $local ret_status="%(?:%{$fg_bold[green]%}>:%{$fg_bold[red]%}>%s)“PROMPT=’${ret_status} %{$fg[cyan]%}%c%{$reset_color%} $(git_prompt_info)$ ‘ZSH_THEME_GIT_PROMPT_PREFIX=”%{$fg_bold[blue]%}git:(%{$fg[red]%}“ZSH_THEME_GIT_PROMPT_SUFFIX=”%{$reset_color%} “ZSH_THEME_GIT_PROMPT_DIRTY=”%{$fg[blue]%}) %{$fg[yellow]%}x%{$reset_color%}“ZSH_THEME_GIT_PROMPT_CLEAN=”%{$fg[blue]%})"# ~/.zshrcZSH_THEME=“robbyrussell-ascii"plugins=(git zsh-completions zsh-autosuggestions zsh-syntax-highlighting)6.3 安装多个发行版Windows 10 Fall Creators Update 之后,WSL 支持同时安装多个 Linux 发行版,直接在 Microsoft Store 中搜索想要的发行版并点击安装即可。这些发行版可以同时运行,并且数据互相独立。你可以使用 wslconfig.exe 来查询已安装的发行版,或者更改默认的发行版。删除发行版也很简单,直接卸载对应的商店应用即可(记得备份哦)。6.4 多种进入 WSL 的方式比较新版支持同时安装多个发行版,那自然不能像以前那样只提供一个 bash.exe 入口了。秋季创意者更新之后的 Windows 提供了 多种进入 WSL 环境的方式:wsl.exe打开默认发行版中的默认 Shell。<distroname>.exe打开指定发行版中的默认 Shell。bash.exe (DEPRECATED)打开默认发行版中的 bash Shell。如果你更改了默认 Shell 却总是打开 bash,就说明你使用了这个入口。你也可以通过这些入口直接在 WSL 中执行命令并返回结果:<distroname> -c [command]bash -c [command]wsl [command](不再需要指定 -c)6.5 与 Windows 的互操作性WSL 与 Windows 之间的互操作性 (Interoperability) 很牛逼。怎么个牛逼法呢?Windows 下的所有盘符都挂载在 WSL 中的 /mnt 目录下,可以直接操作。WSL 中的所有数据则存放于 C:\Users{你的用户名}\AppData\Local\Packages{Linux发行版包名}\LocalState\rootfs 目录中(不要在 Windows 中修改这些文件,这会造成文件权限错误):$ ls /mntc d e$ mount -lrootfs on / type lxfs (rw,noatime)C: on /mnt/c type drvfs (rw,noatime,uid=1000,gid=1000)D: on /mnt/d type drvfs (rw,noatime,uid=1000,gid=1000)E: on /mnt/e type drvfs (rw,noatime,uid=1000,gid=1000)你可以在 Windows 命令行环境中直接调用 WSL 中的命令:PS C:\temp> wsl ls -altotal 0drwxrwxrwx 1 printempw printempw 4096 Sep 7 19:04 .drwxrwxrwx 1 printempw printempw 4096 Sep 7 18:38 ..-rwxrwxrwx 1 printempw printempw 4 Sep 7 19:04 foo.txt你也可以在 WSL 中调用 Windows 中的命令行程序:$ which ipconfig.exe/mnt/c/Windows/System32/ipconfig.exe$ ipconfig.exeWindows IP Configuration…你可以在 WSL 中直接启动 Windows 应用:$ notepad.exe “C:\temp\foo.txt"你还可以通过 pipes 与 Windows 程序通信:# 复制内容至 Windows 剪贴板$ cat foo.txt | clip.exe你甚至可以把 Windows 命令和 WSL 命令混着用:PS> ipconfig | wsl grep IPv4IPv4 Address. . . . . . . . . . . : 192.168.1.114$ ipconfig.exe | grep IPv4 | cut -d: -f2192.168.1.114$ ls -al | findstr.exe foo.txt-rwxrwxrwx 1 printempw printempw 4 Sep 7 19:04 foo.txt$ cmd.exe /c dir Volume in drive C is Windows Volume Serial Number is B263-**** Directory of C:\temp2018/09/07 19:04 <DIR> .2018/09/07 19:04 <DIR> ..2018/09/07 19:04 4 foo.txt 1 File(s) 4 bytes 2 Dir(s) 194,422,341,632 bytes free同时,WSL 与 Windows 共享网络栈,也就是说你可以:在 WSL 中启动 web server,在 Windows 上使用浏览器访问;在 Windows 下启动 MySQL/Redis 服务器,在 WSL 中连接;诸如此类。如果你对 WSL 与 Windows 之间互操作的原理有兴趣,可以参考一下这些文章:WSL interoperability with WindowsWindows and Ubuntu Interoperability6.6 DrvFs 文件权限问题虽然 WSL 中可以直接访问 Windows 磁盘的内容,但如果你曾经这么做过,你应该对这样绿油油一片的 ls 不会感到陌生。为什么 NTFS 文件系统中的文件到 WSL 下权限就全部成 0777 了呢?这主要是 DrvFs 中 Linux 文件权限的实现导致的。在 WSL 中,Microsoft 实现了两种文件系统,用于支持不同的使用场景:VolFs着力于在 Windows 文件系统上提供完整的 Linux 文件系统特性,通过各种手段实现了对 Inodes、Directory entries、File objects、File descriptors、Special file types 的支持。比如为了支持 Windows 上没有的 Inodes,VolFs 会把文件权限等信息保存在文件的 NTFS Extended Attributes 中。记得我上面警告过你不要在 Windows 中修改 WSL 里的文件吗?就是因为 Windows 中新建的文件缺少这个扩展参数,VolFs 无法正确获取该文件的 metadata,而且有些 Windows 上的编辑器会在保存时抹掉这些附加参数。WSL 中的 / 使用的就是 VolFs 文件系统。DrvFs着力于提供与 Windows 文件系统的互操作性。与 VolFs 不同,为了提供最大的互操作性,DrvFs 不会在文件的 NTFS Extended Attributes 中储存附加信息,而是从 Windows 的文件权限(Access Control Lists,就是你右键文件 > 属性 > 安全选项卡中的那些权限配置)推断出该文件对应的的 Linux 文件权限。所有 Windows 盘符挂载至 WSL 下的 /mnt 时都是使用的 DrvFs 文件系统。由于 DrvFs 的文件权限继承机制很微妙,最后导致的结果就是所有文件的权限都变成了 0777。而且由于早期的 DrvFs 不支持 metadata,所以你无法给这些文件 chown/chmod,只能对着绿油油的 ls 干瞪眼。不过好消息是,Windows Insider Build 17063 之后,DrvFs 也像 VolFs 一样支持给文件写入 metadata 了。要启用 DrvFs 的 metadata 支持,你需要添加参数重新挂载磁盘:# 修改成你自己的盘符$ sudo umount /mnt/e$ sudo mount -t drvfs E: /mnt/e -o metadata不过如果仅仅是执行了这个,虽然支持了文件权限的修改,但磁盘下的文件权限默认依然还是 0777,除非你给它们整个 chmod 一遍。如果你不想这么做,也可以指定其他的 mount 参数:$ sudo mount -t drvfs E: /mnt/e -o metadata,uid=1000,gid=1000,umask=22,fmask=111这样磁盘下的文件的默认权限就是 0644,ls 也不会再是绿油油一片啦。不过每次使用时都要重新挂载未免也太烦,我们可以通过另一个新特性 Automatically Configuring WSL 实现自动挂载。在 WSL 中创建 /etc/wsl.conf,在其中填写如下内容:[automount]enabled = trueroot = /mnt/options = “metadata,umask=22,fmask=111"mountFsTab = true# 这个文件里还可以添加其他配置项,有兴趣的可以看看上面的链接重启终端,所有的盘符就会使用上面的配置自动挂载啦(可以使用 mount -l 查看)。另外,如果你想要给不同的盘符设定不同的挂载参数(上面的方法对所有盘符都有效,如果你想在 WSL 中运行 Windows 下的应用程序,就得每次都 chmod +x 一下,所以我一般都会把 C: 排除掉),就需要手动修改 /etc/fstab。首先确保 wsl.conf 中的 mountFsTab 为 true,然后编辑 /etc/fstab,添加如下内容:# 不在此列表中的盘符会使用 wsl.conf 中的参数挂载# 格式可以自己去查 fstab 的帮助文档E: /mnt/e drvfs rw,relatime,uid=1000,gid=1000,metadata,umask=22,fmask=111 0 06.7 其他关于 WSL 的折腾虽然 Microsoft 开发 WSL 出来主要是着重于命令行环境的使用,但经过测试,WSL 是可以通过 X Server 执行 GUI 应用程序的,甚至还可以在 WSL 里面用 Wine 执行 Windows 程序……(?????)也有人试过在 WSL 中运行完整的 DE,体验似乎还不错,有兴趣的同学可以去试试。另外,你也可以通过某些神秘的方法用上 Microsoft Store 未提供的 Linux 发行版,比如 Arch Linux。如果你对 WSL 的底层实现有兴趣,也可以去围观一下 WSL 的官方博客:https://blogs.msdn.microsoft….https://blogs.msdn.microsoft….7. 总结虽然 WSL 很不错,但是其比起真正的 Linux 系统还是有很多不足(Docker 等涉及未实现的内核特性的软件无法使用,Raw socket 相关的操作依然容易出错,I/O 性能相比之下较为孱弱等)。如果你日常开发中需要使用到那些 WSL 未提供的 Linux 特性,那么还是乖乖跑 VM 或者装 Linux 吧。对我来说,WSL 最大的意义就是,让我能够用我熟悉的 Linux 那一套去操作 Windows。如果你和我的需求一样,那么比起 Cygwin、VM 等解决方案,WSL 有着完整的 Linux 环境、强大的互操作性、更低的资源占用。离不开 Windows,却又羡慕 Linux 下强大命令行工具的各位,相信你们会喜欢 WSL 的。而且最近几年 Microsoft 在笼络开发者方面的努力大家有目共睹,这里就容我夸上一句:Microsoft,干得漂亮! ...

October 15, 2018 · 5 min · jiezi

从 1 到完美,用 node 写一个命令行工具

从 1 到完美,用 node 写一个命令行工具1. package.json 中的 bin 字段现在,不管是前端项目还是 node 项目,一般都会用 npm 做包管理工具,而 package.json 是其相关的配置信息。对 node 项目而言,模块导出入口文件由 package.json 的 main 字段指定,而如果是要安装到命令行的工具,则是由 package.json 的 bin 字段指定。1.1 配置单个命令与包名同名{ “name”: “pro”, “bin”: “bin/pro.js”}这样安装的命令名称就是 pro。自定义命令名称(与包名不同名){ “name”: “pro-cli”, “bin”: { “pro”: “bin/pro.js” }}这样安装的命令名称也是 pro。1.2 配置多个命令{ “name”: “pro-cli”, “bin”: { “pro”: “bin/pro.js”, “mini”: “bin/mini.js” }}这样安装就有 pro 与 mini 两个命令。2. 对应 bin/pro.js 文件的写法#!/usr/bin/env noderequire(’../lib/pro’);与普通的 js 文件写法一样,只是前面要加上 #!/usr/bin/env node。这段前缀代码叫 shebang,具体可以参考 Shebang (Unix) - Wikipedia).3. 安装方式3.1 全局安装npm i -g pro-cli这种安装方式可以在命令行全局使用。pro devpro build3.2 本地安装npm i –save-dev pro-cli这种安装方式需要配合 npm 一起使用,比如:# package.json{ “scripts”: { “dev”: “pro dev”, “build”: “pro build” }}# 使用npm run devnpm run build4. 选择合适的命令行封装库一般来说,一个命令都会有如下的一些参数:-v, –version 或 -V, –version: 查看版本号-h, –help: 查看帮助信息如果完全自己来写的,就会很麻烦,尤其是帮助信息。所以,选择一个好的命令行封装库,能够帮我们省去很多工作。用的比较多的:commander.jsyargsmeow以 commander.js 为例:4.1 安装npm install commander –save4.2 注册const commander = require(‘commander’);注册版本号与描述commander .version(‘0.0.1’) .description(‘A cli application named pro’);注册参数(非子命令参数)commander .option(’-p, –peppers’, ‘Add peppers’) .option(’-P, –pineapple’, ‘Add pineapple’) .option(’-b, –bbq-sauce’, ‘Add bbq sauce’) .option(’-c, –cheese [type]’, ‘Add the specified type of cheese [marble]’, ‘marble’)注册子命令commander .command(‘rm <dir>’) .option(’-r, –recursive’, ‘Remove recursively’) .action((dir, cmd) => { console.log(‘remove ’ + dir + (cmd.recursive ? ’ recursively’ : ‘’)) })解析commander.parse(process.argv);4.3 使用查看版本号pro -Vpro –version# 打印结果0.0.1运行 rm 子命令pro rm dir查看帮助(commander 会自动生成)pro -hpro –help# 打印结果Usage: pro [options]A cli application named proOptions: -h, –help output usage information -V, –version output the version number -p, –peppers Add peppers -P, –pineapple Add pineapple -b, –bbq Add bbq sauce -c, –cheese <type> Add the specified type of cheese [marble] -C, –no-cheese You do not want any cheese更多用法查看 commander.js。5. 常用的命令行相关工具库5.1 minimist: 解析命令行的参数var argv = require(‘minimist’)(process.argv.slice(2));console.dir(argv);$ node example/parse.js -a beep -b boop{ _: [], a: ‘beep’, b: ‘boop’ }$ node example/parse.js -x 3 -y 4 -n5 -abc –beep=boop foo bar baz{ _: [ ‘foo’, ‘bar’, ‘baz’ ], x: 3, y: 4, n: 5, a: true, b: true, c: true, beep: ‘boop’ }更多参考 minimist。5.2 chalk: 让命令行的字符带上颜色更多参考 chalk。5.3 Inquirer.js: 让命令行与用户进行交互,如输入、选择等更多参考 Inquirer.js。5.4 shelljs: 跨平台 Unix shell 命令 的 node 封装var shell = require(‘shelljs’);if (!shell.which(‘git’)) { shell.echo(‘Sorry, this script requires git’); shell.exit(1);}// Copy files to release dirshell.rm(’-rf’, ‘out/Release’);shell.cp(’-R’, ‘stuff/’, ‘out/Release’);// Replace macros in each .js fileshell.cd(’lib’);shell.ls(’*.js’).forEach(function (file) { shell.sed(’-i’, ‘BUILD_VERSION’, ‘v0.1.2’, file); shell.sed(’-i’, /^.REMOVE_THIS_LINE.$/, ‘’, file); shell.sed(’-i’, /.REPLACE_LINE_WITH_MACRO.\n/, shell.cat(‘macro.js’), file);});shell.cd(’..’);// Run external tool synchronouslyif (shell.exec(‘git commit -am “Auto-commit”’).code !== 0) { shell.echo(‘Error: Git commit failed’); shell.exit(1);}更多参考 shelljs。5.5 blessed-contrib: 命令行图表更多参考 blessed-contrib。5.6 cash: 跨平台 linux 命令 的 node 封装与 shelljs 功能差不多。const $ = require(‘cash’);const out = $.ls(’.’, {l: true});更多参考 cash。5.7 prompts: 又一个让命令行与用户进行交互的工具与 Inquirer.js 功能差不多。更多参考 prompts。5.8 ora: 命令行加载中图标更多参考 ora。5.9 progress: 命令行进度条downloading [===== ] 39/bps 29% 3.7s更多参考 progress。5.10 更多更多关于命令行的工具库可以参考 command-line-utilities。6. 比较常用的命令行 APP命令行相关的应用就很多啦,比如 babel、webpack、rollup、eslint 等,但这些不仅仅是命令行工具。下面介绍一些纯命令行应用:vtop: 美美的 linux top 命令界面speed-test: 测试网络链接速度http-server: 零配置启动一个 http 服务器fkill-cli: 跨平台 kill 命令更多纯命令行应用可以参考 command-line-apps。后续更多博客,查看 https://github.com/senntyou/blogs作者:深予之 (@senntyou)版权声明:自由转载-非商用-非衍生-保持署名(创意共享3.0许可证) ...

September 29, 2018 · 2 min · jiezi