最近写脚本比较多,然后经常写命令行相关的代码,记录一下以备万一。
首先,node使用命令行依赖于child_process,这个是node原生支持的,我用的最多就是exec。
按顺序执行多个命令
因为写脚本需要执行多个语句,所以写了一个方法来执行,一个成功了,然后继续执行下一个。
const { exec } = require('child_process')
const util = require('util');
const execPromise = util.promisify(exec)
var commands = [
'mkdir test',
'mkdir test2',
]
execCommands(commands)
async function execCommands(commands) {
let index = 0
try {
for (let i = 0; i < commands.length; i++) {
index = i
const command = commands[i];
const res = await execPromise(command)
console.log('exec command success', index, '[', commands[index], ']', '\n value:', res)
}
} catch (error) {
console.error('exec command fail at:', index, '[', commands[index], ']', '\n error:', error)
}
}
复制代码
但是这样还有一个问题,那就是命令的执行位置,如果你使用cd
命令,那么你第一想法可能是先进入那个目录,然后在该目录下执行命令。在cmd里面大概是这样cd .. && mkdir test2
,此时构建node代码如下:
var commands = [ 'cd ..', 'mkdir test2',]
复制代码
但是实际执行结果却不太对,因为对于exec
方法而言,每次路径都需要从当前目录开始算。
当前目录:命令行当前所在路径。也是Node.js 进程的当前工作目录。
文件目录:脚本文档所在目录
两者不一样,比如你在系统根目录
/
执行了node ./path/test/shell.js
,那么当前目录就是/
,文件目录就是./path/test/
为了解决跨目录执行命令的问题,你可以
var commands = [ 'cd .. && mkdir test2',]
复制代码
这是最简单的。
支持切换当前目录
但是试想每次你测试命令行语句都是在cmd终端里,如果每次都要比cmd里面多写一些cd
命令,明显会耽误时间。达不到ctrl+c+v
的丝滑感受。我既然写了这个文章那就不能不追求完美。
既然要改变当前目录,那么根据上面的经验,最简单的方法就是在每一个命令之前加cd
。 但是这个cd
怎么来呢?答案是,记录当前位置的绝对路径,然后通过算cd
命令和当前目录。更改当前位置的绝对路径。当然因为记录了当前位置,cd
命令不再执行。
让我们demo一下
let curAbsPath = process.cwd() // 获取当前目录
// blah blah blah
// 每次执行cd命令,不执行exec了
const cdCommand = 'cd ./demo'
curAbsPath = path.resolve(curAbsPath,cdCommand.replace('cd ',''))
// 每次执行非cd命令
let newCommand = `cd ${curAbsPath} && ` + command
const res = execPromise(newCommand)
复制代码
那么完整的代码如下:
const { exec } = require('child_process')
const util = require('util');
const path = require('path');
const execPromise = util.promisify(exec)
var commands = [
'cd ../tripdocs-js-sdk',
'mkdir test2',
'mkdir test3',
]
execCommands(commands)
async function execCommands(commands) {
let curAbsPath = process.cwd() // 获取当前目录
let index = 0
try {
for (let i = 0; i < commands.length; i++) {
index = i
const command = commands[i];
if (command.startsWith('cd ')) {
// 每次执行cd命令,不执行exec了
curAbsPath = path.resolve(curAbsPath, command.replace('cd ', ''))
continue
}
// 每次执行非cd命令
let newCommand = `cd ${curAbsPath} && ` + command
const res = await execPromise(newCommand)
console.log('exec command success', index, '[', commands[index], ']', '\n value:', res)
}
} catch (error) {
console.error('exec command fail at:', index, '[', commands[index], ']', '\n error:', error)
}
}
复制代码
是不是很简单呢?