package a_executor import ( "bufio" "bytes" "errors" "fmt" "io" "net/http" "net/url" "os" "os/exec" "path/filepath" "regexp" "strings" "golang.org/x/net/proxy" ) var RemoveForcePrefix = []string{"rm", "-rf"} // BasicCommandExists 判定命令是否存在 func BasicCommandExists(commandName string) bool { cmd := exec.Command("command", "-v", commandName) err := cmd.Run() if err != nil { log.DebugF("指令 %s 不存在 => %s", commandName, err.Error()) return false } else { return true } } // BasicCommandExistsBatch 判定批量命令是否存在 func BasicCommandExistsBatch(commandNameList []string) (bool, string) { for _, commandName := range commandNameList { if !BasicCommandExists(commandName) { return false, commandName } } return true, "" } // BasicCommandExistByPath 根据路径判定 命令是否存在 func BasicCommandExistByPath(commandName string) bool { if BasicFileExistInFolder(commandName, "/usr/local/sbin", "/usr/local/bin", "/usr/sbin", "/usr/bin", "/sbin", "/bin", "/snap/bin") { return true } return false } // BasicFileExistInFolder 查询fileName是否存在于目录folderList中,如果存在返回true,不存在返回false func BasicFileExistInFolder(fileName string, folderList ...string) bool { if fileName == "" { return false // If the file name is empty, we cannot check for existence. } for _, folder := range folderList { if folder == "" { continue // Skip empty folders. } if BasicFolderExists(folder) { // is folder ok, _ := PipelineCommandExecutor([][]string{ { "ls", folder, }, { "grep", "-c", fileName, }, }) if ok { return true } } } return false } func BasicGrepItemInFile(item string, fileName string) bool { if !BasicFileExistAndNotNull(fileName) { log.ErrorF("[BasicGrepItemInFile] - fileName [ %s ] not exits !", fileName) return false } ok, _ := PipelineCommandExecutor([][]string{ { "cat", fileName, }, { "grep", "-q", item, }, }) if ok { return true } return false } func BasicFindContentInFile(content string, fileName string) bool { // Open the file file, err := os.Open(fileName) if err != nil { log.ErrorF("[BasicFindContentInFile] - file not exits !") return false } defer file.Close() // Create a scanner to read the file line by line scanner := bufio.NewScanner(file) // Set the split function for the scanner scanner.Split(bufio.ScanLines) // Iterate over the lines of the file for scanner.Scan() { // Get the current line line := scanner.Text() // Check if the current line contains the search term if strings.Contains(line, content) { return true } } // Check for any errors that occurred during scanning if err := scanner.Err(); err != nil { log.ErrorF("[BasicFindContentInFile] - scanner error ! %s", err.Error()) } return false } func BasicFindAndDeleteContendLineInFile(content string, fileName string) bool { // Open the file file, err := os.Open(fileName) if err != nil { log.ErrorF("[FindDeleteContendLineInFile] - file not exits !") return false } defer file.Close() // Create a scanner to read the file line by line scanner := bufio.NewScanner(file) // Set the split function for the scanner scanner.Split(bufio.ScanLines) // 创建一个新的文件内容变量 var newContent string // Iterate over the lines of the file for scanner.Scan() { // Get the current line line := scanner.Text() // Check if the current line contains the search term if !strings.Contains(line, content) { newContent += line + "\n" } } // Check for any errors that occurred during scanning if err := scanner.Err(); err != nil { log.ErrorF("[BasicFindContentInFile] - scanner error ! %s", err.Error()) return false } // 将修改后的内容写回文件 err = os.WriteFile(fileName, []byte(newContent), os.ModePerm) if err != nil { log.ErrorF("[FindDeleteContendLineInFile] - write file %s error with contend %s", fileName, newContent) return false } return true } func BasicFindContentInCommandOutput(hardCodeCommand string, content string) (bool, []string) { ok, resultLog := HardCodeCommandExecutor(hardCodeCommand) if !ok { log.ErrorF("[BasicFindContentInCommandOutput] - command error ! => %v", resultLog) return false, nil } return BasicFindContentInList(content, resultLog), resultLog } func BasicFindContentInList(content string, list []string) bool { for _, item := range list { if strings.Contains(item, content) { return true } } return false } func BasicDockerImageExistByFullName(imageFullName string) bool { var imageVersion string split := strings.Split(imageFullName, ":") imageVersion = split[len(split)-1] imageFullName = strings.TrimSuffix(imageFullName, ":"+imageVersion) //log.DebugF("[BasicDockerImageExistByFullName] -- %s %s", imageFullName, imageVersion) return BasicDockerImageExists(imageFullName, imageVersion) } func BasicDockerImageExists(imageName, imageVersion string) bool { if !BasicCommandExistByPath("docker") { return false } ok, _ := PipelineCommandExecutor([][]string{ { "docker", "image", "ls", }, { "grep", imageName, }, { "grep", "-q", imageVersion, }, }) if !ok { return false } return true } func BasicInstallSoftware(installPrefix []string, isStrict bool, softwares ...string) (bool, []string) { var installLog []string for _, software := range softwares { log.DebugF("[BasicInstallSoftware] - going to install [ %s ]", software) if !PureResultSingleExecute(append(installPrefix, software)) { failedInstall := fmt.Sprintf("[BasicInstallSoftware] - software of [ %s ] install failed !", software) installLog = append(installLog, failedInstall) if isStrict { return false, installLog } } successInstall := fmt.Sprintf("[BasicInstallSoftware] - software of [ %s ] install success !", software) installLog = append(installLog, successInstall) } return true, installLog } // BasicReplace 将文件中origin字段全部替换为replace func BasicReplace(filename string, origin string, replace string) bool { if !BasicFileExistAndNotNull(filename) { log.WarnF("文件替换 文件不存在 %s", filename) return false } // 打开文件 file, err := os.OpenFile(filename, os.O_RDWR, 0644) if err != nil { fmt.Printf("error opening file: %v\n", err) return false } // 创建一个临时文件用于存储替换后的内容 tempFilename := filename + ".tmp" tempFile, err := os.Create(tempFilename) if err != nil { fmt.Printf("error creating temp file: %v\n", err) return false } scanner := bufio.NewScanner(file) for scanner.Scan() { line := scanner.Text() // 使用正则表达式替换,以支持多种替换场景(如部分词、多行等) re := regexp.MustCompile(fmt.Sprintf("(\\b%s\\b)|(^%s)|(%s$)", origin, origin, replace)) newLine := re.ReplaceAllString(line, replace) // 写入替换后的内容到临时文件 _, err := tempFile.WriteString(newLine + "\n") if err != nil { fmt.Printf("error writing to temp file: %v\n", err) return false } } // 检查是否有错误发生 if err := scanner.Err(); err != nil { fmt.Printf("error reading from file: %v\n", err) return false } err = file.Close() if err != nil { log.ErrorF("error closing file: %v\n", err) return false } err = tempFile.Close() if err != nil { log.ErrorF("error closing file: %v\n", err) return false } // 移动文件名,指向新的替换后的文件 err = os.Remove(filename) if err != nil { log.ErrorF("error removing file: %v\n", err) return false } err = os.Rename(tempFilename, filename) if err != nil { fmt.Printf("error renaming file: %v\n", err) return false } // 返回成功标志 return true } // BasicReplaceBySed 基础替换命令 func BasicReplaceBySed(filename string, origin string, replace string) bool { // 暂不添加 //if !BasicFileExistAndNotNull(filename) { // log.DebugF("文件替换") //} cmd := exec.Command("sed", "-i", "s/"+origin+"/"+replace+"/g", filename) err := cmd.Run() if err != nil { log.DebugF("替换文件 %s ,从 [%s] => [%s] 错误!", filename, origin, replace) return false } else { return true } } func BasicRemoveFolderComplete(folderName string) bool { err := filepath.Walk(folderName, func(path string, info os.FileInfo, err error) error { if err != nil { return err } if !info.IsDir() { return os.Remove(path) } return nil }) if err != nil { return false } err = os.RemoveAll(folderName) if err != nil { return false } return true } // BasicFileExists 检测文件是否存在 func BasicFileExists(filename string) bool { if filename == "" { return false // An empty string does not correspond to a valid file. } _, err := os.Stat(filename) if err != nil { switch err.(type) { case *os.PathError: // If the error is because the path doesn't exist, return false. if errors.Is(err.(*os.PathError).Err, os.ErrNotExist) { log.DebugF("文件 %s 不存在!", filename) return false } case nil: return true default: // Handle other types of errors as appropriate for your use case. return false } } return true } // BasicFileExistAndNotNull 文件不为空返回true 文件为空返回false func BasicFileExistAndNotNull(filename string) bool { // 获取文件信息 fileInfo, err := os.Stat(filename) if err != nil { // 如果文件不存在或其他错误,返回 false return false } // 检查文件大小是否大于零 return fileInfo.Size() > 0 } func BasicFolderExists(folderName string) bool { fi, err := os.Stat(folderName) if err != nil { if os.IsNotExist(err) { // 目标路径不存在 log.WarnF("[BasicFolderExists] - 目录 %s 不存在!", folderName) return false } // 其他错误 return false } // 判断是否为目录 return fi.IsDir() } func BasicCreateFolder(folderName string) bool { // 检查目录是否存在 if _, err := os.Stat(folderName); os.IsNotExist(err) { // 目录不存在,创建目录 err := os.MkdirAll(folderName, os.ModePerm) if err != nil { // 如果创建目录失败,返回false return false } } // 目录存在或者成功创建,返回true return true } func BasicRemoveFileOrFolder(folderName string) bool { // Check if the folder exists if _, err := os.Stat(folderName); os.IsNotExist(err) { return true // folder does not exist } // Folder exists, remove it err := os.Remove(folderName) if err != nil { // Handle error return false } return true // folder was removed } // BasicPrettyPrint 打印执行结果 func BasicPrettyPrint(resultOk bool, resultLog []string) { fmt.Printf("resultOK is => %#v\n", resultOk) if resultLog == nil || len(resultLog) == 0 { return } for _, s := range resultLog { fmt.Println(s) fmt.Println() } } // BasicSystemdShutdown 使用Systemd关闭服务,会判定服务器是否存在 func BasicSystemdShutdown(serviceName string) (ok bool, resultLog []string) { if !strings.HasSuffix(serviceName, ".service") { serviceName = serviceName + ".service" } // 检查是否存在 existService := BasicFileExistInFolder(serviceName, "/lib/systemd/system/", "/etc/systemd/system") if !existService { return true, []string{ serviceName, "该服务不存在!", } } // 关闭 var shutDownCommand = [][]string{ { "systemctl", "stop", serviceName, }, { "sleep", "1", }, { "systemctl", "disable", serviceName, }, } resultOK := PureResultSingleExecuteBatch(shutDownCommand) return resultOK, resultLog } // BasicSystemdUp 使用Systemd启动服务,会判定服务器是否存在 func BasicSystemdUp(serviceName string) (ok bool, resultLog []string) { if !strings.HasSuffix(serviceName, ".service") { serviceName = serviceName + ".service" } // 检查是否存在 existService := BasicFileExistInFolder(serviceName, "/lib/systemd/system/", "/etc/systemd/system") if !existService { return true, []string{ serviceName, "该服务不存在!", } } // 关闭 var shutDownCommand = [][]string{ { "systemctl", "start", serviceName, }, { "sleep", "1", }, { "systemctl", "enable", serviceName, }, } resultOK := PureResultSingleExecuteBatch(shutDownCommand) return resultOK, resultLog } // BasicTransPipelineCommand 转换手写的管道命令为可执行的形式 func BasicTransPipelineCommand(pipelineString string) (pipelineCommand [][]string) { var pipelineCommandC [][]string split := strings.Split(pipelineString, "|") if len(split) == 0 { log.WarnF("输入的pipelineString有误! %s", pipelineString) return pipelineCommandC } for _, s := range split { // 去除掉无效的空行 singleCommand := strings.Split(s, " ") var realSingleCommand []string for i := range singleCommand { if singleCommand[i] != "" { realSingleCommand = append(realSingleCommand, singleCommand[i]) } } pipelineCommandC = append(pipelineCommandC, realSingleCommand) } return pipelineCommandC } func BasicConvertBufferToSlice(outputBuffer bytes.Buffer) (resultLog []string) { s := outputBuffer.String() split := strings.Split(s, "\n") return split } func BasicDownloadFile(downloadUrl string, socksProxyUrl string, proxyUser string, proxyPass string, desFile string) (downloadOk bool, resultLog []string) { // 解析下载URL _, err := url.Parse(downloadUrl) if err != nil { resultLog = append(resultLog, "Error parsing download URL: "+err.Error()) return false, resultLog } // 创建文件 out, err := os.Create(desFile) if err != nil { resultLog = append(resultLog, "Error creating file: "+err.Error()) return false, resultLog } defer out.Close() // 创建HTTP客户端 client := &http.Client{} // 如果提供了代理URL if socksProxyUrl != "" { // 解析代理URL parsedProxyUrl, err := url.Parse(socksProxyUrl) if err != nil { resultLog = append(resultLog, "Error parsing proxy URL: "+err.Error()) return false, resultLog } // 使用SOCKS5代理 auth := &proxy.Auth{User: proxyUser, Password: proxyPass} dialer, err := proxy.SOCKS5("tcp", parsedProxyUrl.Host, auth, proxy.Direct) if err != nil { resultLog = append(resultLog, "Error creating SOCKS5 dialer: "+err.Error()) return false, resultLog } // 设置HTTP和HTTPS代理 httpTransport := &http.Transport{ Dial: dialer.Dial, } client.Transport = httpTransport } // 发送HTTP GET请求 resp, err := client.Get(downloadUrl) if err != nil { resultLog = append(resultLog, "Error making GET request: "+err.Error()) return false, resultLog } defer resp.Body.Close() // 检查HTTP响应状态码 if resp.StatusCode != http.StatusOK { resultLog = append(resultLog, "Server returned HTTP status "+resp.Status) return false, resultLog } // 将HTTP响应内容写入文件 _, err = io.Copy(out, resp.Body) if err != nil { resultLog = append(resultLog, "Error writing to file: "+err.Error()) return false, resultLog } // check file exists existAndNotNull := BasicFileExistAndNotNull(desFile) if !existAndNotNull { return false, []string{ "[BasicDownloadFile] - file not exist download error!", } } return true, resultLog } // BasicDownloadFileByCurl 从目标地址下载文件到目的地,并检测文件是否下载成功 func BasicDownloadFileByCurl(downloadUrl, desFile string) (downloadOk bool, resultLog []string) { // wget or curl download var ok bool if BasicCommandExistByPath("wget") { ok, resultLog = AllCommandExecutor([]string{ "wget", "--no-check-certificate", "--timeout=5", downloadUrl, "-qO", desFile, }) } else if BasicCommandExistByPath("curl") { ok, resultLog = AllCommandExecutor([]string{ "curl", "-o", desFile, "--insecure", "--max-time", "5", downloadUrl, }) } else { sprintf := fmt.Sprintf("[BasicDownloadFileByCurl] - neither wget or curl exists ! can't download file [ %s ] from [ %s ]", desFile, downloadUrl) log.Error(sprintf) return false, []string{ sprintf, } } errLog := fmt.Sprintf("[BasicDownloadFileByCurl] - download file [ %s ] from [ %s ] failed !", desFile, downloadUrl) if !ok { log.Error(errLog) return false, []string{ errLog, } } // check file exists existAndNotNull := BasicFileExistAndNotNull(desFile) if !existAndNotNull { return false, []string{ errLog, "[BasicDownloadFileByCurl] - file not exist !", } } return true, nil } func BasicDownloadFileWithProxy(downloadUrl, proxyUrl, desFile string) (downloadOk bool, resultLog []string) { var ok bool if !BasicCommandExistByPath("curl") { return false, []string{ "curl not exits!", } } ok, resultLog = AllCommandExecutor([]string{ "curl", "-x", proxyUrl, "-o", desFile, "--insecure", "--max-time", "5", downloadUrl, }) errLog := fmt.Sprintf("[BasicDownloadFileWithProxy] - download file [ %s ] with proxy [ %s ] from [ %s ] failed !", desFile, proxyUrl, downloadUrl) if !ok { log.Error(errLog) return false, []string{ errLog, } } // check file exists existAndNotNull := BasicFileExistAndNotNull(desFile) if !existAndNotNull { return false, []string{ errLog, "[BasicDownloadFileByCurl] - file not exist !", } } return true, nil } // BasicAppendSourceToFile 将源文件的内容添加到目标文件,使用golang标准库完成,跨平台、安全性更强 func BasicAppendSourceToFile(sourceFile, targetFile string) bool { // 打开源文件 source, err := os.Open(sourceFile) if err != nil { log.ErrorF("[BasicAppendSourceToFile] - error open source file => %s, error is %s", sourceFile, err.Error()) return false } defer source.Close() // 打开目标文件,如果不存在则创建,如果存在则在末尾追加 target, err := os.OpenFile(targetFile, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644) if err != nil { log.ErrorF("[BasicAppendSourceToFile] - error open target file => %s, error is %s", sourceFile, err.Error()) return false } defer target.Close() // 将源文件内容复制到目标文件 _, err = io.Copy(target, source) if err != nil { log.ErrorF("[BasicAppendSourceToFile] - Error appending to target file: %s", err.Error()) return false } return true } // BasicAppendContentToFile 向目标文件中追加写入一些内容 func BasicAppendContentToFile(content string, targetFile string) bool { // 打开文件用于追加。如果文件不存在,将会创建一个新文件。 file, err := os.OpenFile(targetFile, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644) if err != nil { log.ErrorF("[BasicAppendContentToFile] - Error opening file: %s , error is %s", targetFile, err.Error()) return false } defer file.Close() // 确保文件最终被关闭 // 写入内容到文件 if _, err := file.WriteString(content); err != nil { log.ErrorF("[BasicAppendContentToFile] - Error writing to file: %s , error is %s", targetFile, err.Error()) return false } return true } // BasicAppendOverwriteContentToFile 向目标文件中写入一些内容,覆盖源文件 func BasicAppendOverwriteContentToFile(content string, targetFile string) bool { err := os.Remove(targetFile) if err != nil { log.WarnF("[BasicAppendOverwriteContentToFile] - Error removing file: %s , error is %s", targetFile, err.Error()) } return BasicAppendContentToFile(content, targetFile) } // BasicAppendNullToFile 清空一个文件 func BasicAppendNullToFile(targetFile string) bool { // 使用os.O_TRUNC清空文件内容 file, err := os.OpenFile(targetFile, os.O_TRUNC|os.O_WRONLY, 0644) if err != nil { log.ErrorF("[BasicAppendNullToFile] - Error opening file: %s, error is %s", targetFile, err.Error()) return false } defer file.Close() // 确保在函数退出前关闭文件 return true } func BasicWordSpaceCompletion(source string, totalLength int) string { sourceLength := len(source) if sourceLength >= totalLength { return source } for i := 0; i < totalLength-sourceLength; i++ { source += " " } return source }