go中使用cmd与crontab

一、go中使用cmd

/bin/bash -c “ls -l”

cmd->golang->pipe

pipe()创建2个文件描述符,fd[0]可读,fd[1]可写
fork() 创建子进程 fd[1]被继承到子进程
dup2() 重定向子进程 stdout/stderr到fd[1]
exec() 在当前进程内,加载并执行二进制程序

例子1

模拟一下cmd调用

package main

import (
	"fmt"
	"os/exec"
)

func main()  {
	var(
		cmd *exec.Cmd
		output []byte
		err error
	)
	//cmd = exec.Command("/bin/bash","-c","cd /tmp;ls -l")
	cmd = exec.Command("/bin/bash","-c","sleep 5;echo baidu.com")

	if output,err = cmd.CombinedOutput();err!=nil{
		fmt.Println(err)
		return
	}
	fmt.Println(string(output))
}


例子2

模拟调用cmd时,杀死bash进程

package main

import (
	"context"
	"fmt"
	"os/exec"
	"time"
)
type result struct {
	err error
	output []byte
}
func main()  {
	var(
		ctx context.Context
		cancelFunc context.CancelFunc
		cmd *exec.Cmd
		resultChan chan *result
		res *result
	)
	//创建一个结果对列
	resultChan = make(chan *result,1000)
	//context chan byte
	//cnacelFnc: close(chan byte)
	ctx,cancelFunc  = context.WithCancel(context.TODO())
	go func() {
		var(
			output [] byte
			err error
		)
		//select {case <-ctx.Done}
		// 监听到 select中有<-ctx.Done 就杀掉当前的命令 pid , kill bash
		cmd = exec.CommandContext(ctx,"/bin/bash","-c","sleep 2;echo hello;")

		//执行任务,捕获输出
		output,err = cmd.CombinedOutput()
		//任务输出结果 传给main协程
		resultChan <- &result{
			err:    err,
			output: output,
		}
	}()

	time.Sleep(time.Second*1) //这里1秒后就要将content关闭,所以bash进程会被杀死
	cancelFunc()
	res = <-resultChan

	fmt.Println(res.err,string(res.output))
}

二、go中使用cron

Cron基本格式

shell命令
*/5 * * * * echo hello >/tmp/x.log
1-5 * * * * echo /usr/bin/python /data/x.py
0 10,22 * * * echo hello

go开源Cronexpr库
Parse() 解析与校验Cron表达式
Next() 根据当前时间,计算下一次调度时间

例子1

模拟一下cron调用

package main

import (
	"fmt"
	"github.com/gorhill/cronexpr"
	"time"
)

func main()  {
	var(
		expr *cronexpr.Expression
		err error
		now time.Time
		nextTime time.Time
	)
	if expr,err = cronexpr.Parse("*/5 * * * * * *");err!=nil{
		fmt.Println(err)
		return
	}

	now = time.Now()
	//下次调度时间
	nextTime = expr.Next(now)
	//多长时间后运行
	time.AfterFunc(nextTime.Sub(now), func() {
		fmt.Println("被调度了:",nextTime)
	})

	time.Sleep(time.Second*5)

}

执行结果

被调度了: 2020-02-05 17:19:25 +0800 CST

例子2

模拟多个cron调用

package main

import (
	"fmt"
	"github.com/gorhill/cronexpr"
	"time"
)

type CronJob struct {
	expr     *cronexpr.Expression
	nextTime time.Time
}

func main() {

	var (
		cronJob       *CronJob
		expr          *cronexpr.Expression //表达式
		now           time.Time
		scheduleTable map[string]*CronJob //任务表
	)
	scheduleTable = make(map[string]*CronJob)
	//当前时间
	now = time.Now()
	//Cron表达式
	expr = cronexpr.MustParse("*/5 * * * * * *")
	cronJob = &CronJob{
		expr:     expr,
		nextTime: expr.Next(now),
	}
	//任务注册到任务表中
	scheduleTable["job1"] = cronJob

	expr = cronexpr.MustParse("*/5 * * * * * *")
	cronJob = &CronJob{
		expr:     expr,
		nextTime: expr.Next(now),
	}
	//任务注册到任务表中
	scheduleTable["job2"] = cronJob

	// 需要有1个调度协程,它定时检查所有的Cron任务,谁过期就执行谁
	go func() {
		var (
			jobName string
			cronJob *CronJob
			now     time.Time
		)
		//定时看任务表
		for {
			now = time.Now()
			for jobName, cronJob = range scheduleTable {
				if cronJob.nextTime.Before(now) || cronJob.nextTime.Equal(now) {
					//启动一个协程,执行这个任务
					go func(jobName string) {
						fmt.Println("执行:", jobName)
					}(jobName)

					//计算下一次执行时间
					cronJob.nextTime = cronJob.expr.Next(now)
					fmt.Println(jobName, "下次执行时间:", cronJob.nextTime)
				}
			}

			//这里模拟一下休眠
			select {
			case <-time.NewTimer(time.Millisecond*100).C: //100毫秒可读,返回

			}
		}
	}()

	time.Sleep(time.Second*100)
}

执行结果

执行: job1
job1 下次执行时间: 2020-02-05 17:08:55 +0800 CST
job2 下次执行时间: 2020-02-05 17:08:55 +0800 CST
执行: job2
执行: job1
job1 下次执行时间: 2020-02-05 17:09:00 +0800 CST
job2 下次执行时间: 2020-02-05 17:09:00 +0800 CST


你可能感兴趣的:(golang)