好久没上来这里写专栏了,发现上一篇有关tar打包解包还留着一个坑。这里补上。
本文介绍下通过os/exec调用shell命令,直接调用系统的tar命令进行打包。
方案二、通过调用系统的tar命令
基本思路是先拼接tar打包和解包的命令,然后调用os/exec包的CommandContext方法执行shell命令。这里要求操作系统中需要有tar命令。
公共方法的定义
这里定义一个结构体,对日志的读取、shell脚本的执行做了封装。当然如果需要执行其他shell命令,直接给exec方法传入具体命令也是可以的。
代码语言:javascript复制type TgzLinuxPacker struct {
ctx context.Context // context上下文,监听上层的退出信号
cancel context.CancelFunc // context的取消函数
wg sync.WaitGroup
outputList []string // 命令的输出
}
func NewTgzLinuxPacker(ctx context.Context) *TgzLinuxPacker {
subCtx, cancel := context.WithCancel(ctx)
return &TgzLinuxPacker{
ctx: subCtx,
cancel: cancel,
wg: sync.WaitGroup{},
outputList: make([]string, 0),
}
}
// 从标准输出、错误输出读取内容
func (tlp *TgzLinuxPacker) readLog(stdReader io.Reader) {
defer tlp.wg.Done()
reader := bufio.NewReader(stdReader)
for {
select {
case <-tlp.ctx.Done():
return
default:
readString, err := reader.ReadString('n')
if err != nil || err == io.EOF {
return
}
line := strings.Trim(readString, "n")
tlp.outputList = append(tlp.outputList, line)
}
}
}
// 命令执行的封装
func (tlp *TgzLinuxPacker) exec(cmdStr string) error {
// 方法退出时触发cancel方法的调用,通知readLog和shell子进程退出
defer tlp.cancel()
c := exec.CommandContext(tlp.ctx, "/bin/bash", "-c", cmdStr)
// get stdout stderr pipe
stdout, err := c.StdoutPipe()
if err != nil {
return err
}
stderr, err := c.StderrPipe()
if err != nil {
return err
}
// read stdout stderr
tlp.wg.Add(2)
go tlp.readLog(stdout)
go tlp.readLog(stderr)
// 开始执行
err = c.Start()
if err != nil {
return err
}
// 等待readLog退出
tlp.wg.Wait()
// 这里调用一次wait,获取shell进程的退出码
err = c.Wait()
if err != nil {
return errors.New(strings.Join(tlp.outputList, "n") err.Error())
}
if !c.ProcessState.Success() {
return errors.New("返回码:" strconv.Itoa(c.ProcessState.ExitCode()) "n" strings.Join(tlp.outputList, "n"))
}
return nil
}
压缩打包
有了执行shell命令的方法后,我们要进行打包的工作,那就相当简单了,直接拼接命令行即可
代码语言:javascript复制func (tlp *TgzLinuxPacker) Pack(sourceFullPath string, tarFileName string) error {
// e.g: tar -zcf test.tar.gz -C /tmp/ test
cmdStr := "tar -zcf " tarFileName " -C " filepath.Dir(sourceFullPath) " " filepath.Base(sourceFullPath)
return tlp.exec(cmdStr)
}
解压
同压缩打包,值需要拼接解压命令即可
代码语言:javascript复制func (tlp *TgzLinuxPacker) Unpack(tarFileName string, dstDir string) error {
// e.g: tar -zxf /tmp/test.tar.gz -C /tmp/
cmdStr := "tar -zxf " tarFileName " -C " dstDir
return tlp.exec(cmdStr)
}