Golang中使用sed的技巧与实践

Golang中使用sed的技巧与实践 你好,我有一段Linux bash shell代码:

sed -i -e "s/DRUMCLASS/False/g" "/usr/share/OCTAVA/Rich/HTTP/CLASS" &> /dev/null

如何在Go语言中实现它?我在谷歌上搜索过,但没有找到任何相关的结果。

16 回复

没人知道吗? -_- @NobbZ @skillian

更多关于Golang中使用sed的技巧与实践的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


正如我所说,我认为不应该从Go中调用sed,而应该在Go内部完成替换工作。

我不太明白,先生 😑 您说的用 ` 包裹代码是什么意思?

也许可以使用 strings.ReplaceAll(...)

func main() {
    fmt.Println("hello world")
}

顺便问一下,@NobbZ 在 Go 语言中应该如何实现 sed 的功能?我上面的代码正确吗?

如何使用 strings.ReplaceAll() 替换文件中的字符串?我认为通过 ReplaceAll 无法实现。 我希望实现与 sed 相同的方式,并且必须快速。

这正是我写 exec.Cmd 时所做的。

它使代码更易于阅读,并且可以防止软件错误地处理你的引号。

对于构成多行代码的代码块,你可以使用三个反引号:

// Your multiline code
func main() {}

使用 os/exec 库中的 exec.Command(“bash”, “-c”, sed -i -e "s/DRUMCLASS/False/g" "/usr/share/OCTAVA/Rich/HTTP/CLASS" &> /dev/null)。

func main() {
    fmt.Println("hello world")
}

我已经完成了这个功能,并且它运行正常:

func sed(old string, new string, file string) {
	filePath := file
	fileData, _ := ioutil.ReadFile(filePath)
	fileString := string(fileData)
	fileString = strings.ReplaceAll(fileString, old, new)
	fileData = []byte(fileString)
	_ = ioutil.WriteFile(filePath, fileData, 0o600)
}
  1. 修复论坛“美化工具”为你引入的错误。引号是错误的。你们俩都可以通过用反引号包裹代码来避免这个问题:`
  2. 请不要使用那种结构。如果你想用 Go 来做,那就用 Go 的方式来做。如果你到处都使用 exec.Cmd,那你完全可以在 bash 里做。你执行的每一个 exec.Cmd很容易被追踪和恢复。

嗯…我不知道有没有单行的解决方案 也许可以像这样

filePath := "/path/to/somewhere"
fileData, _ := ioutil.ReadFile(filePath)
fileString := string(fileData)
fileString = strings.ReplaceAll(fileString, "old", "new")
fileData = []byte(fileString)
_ = ioutil.WriteFile(filePath, fileData, 0o600)

这应该可行,但我不确定它是否快速/安全/可行

出现错误

command-line-arguments

./5test.go:5:18: 无效的标识符字符 U+201C ‘“’ ./5test.go:5:25: 无效的标识符字符 U+201D ‘”’ ./5test.go:5:30: 无效的标识符字符 U+201C ‘“’ ./5test.go:5:35: 无效的标识符字符 U+201D ‘”’ ./5test.go:5:131: 语法错误:意外的换行符,期望逗号或 )

  1. 你不需要执行 filePath := file
  2. 你需要检查错误 因此,代码应该像这样:
func sed(old, new, filePath string) error {
	fileData, err := ioutil.ReadFile(filePath)
    if err != nil {
          return err
    }

	fileString := string(fileData)
	fileString = strings.ReplaceAll(fileString, old, new)
	fileData = []byte(fileString)

	err = ioutil.WriteFile(filePath, fileData, 0o600)
    if err != nil {
            return err
    }
        
    return nil
}

当我说“用反引号包裹代码”时,我指的是在论坛发帖时这样做,就像你上一篇帖子那样。

要修正出错的代码,只需将语义引号 “” 替换为用于字符串的语法引号 ""

这没什么特别的,在论坛中你将会遇到类似这样的轻微语法问题,你需要自己学会处理这些简单的问题。


不过再次强调,除非必要,否则不要使用 exec.Cmd。在 Go 中,你可以完成 sed 能做的所有事情。

如果你只是不停地链式调用 exec.Cmd,那还不如坚持使用一个简单的 bash 脚本,它的体积会小得多,更容易调试,甚至速度更快!

由于我的英语水平有限,我无法理解 :neutral_face: 实际上您是以另一种方式在说。

exec.Command(“bash”, “-c”, `sed -i -e “s/DRUMCLASS/False/g” “/usr/share/OCTAVA/Rich/HTTP/CLASS” &> /dev/null)`

您能纠正这个吗? 实际上我不明白您在说什么,首先您说在代码中加上反引号,我不确定“加上反引号”是什么意思,我以为您是说在 ) 前面加上反引号,所以我才问您。

兄弟,如果您知道他写的是什么,您能纠正它并用多行代码告诉我吗?就像这样:

exec.Command(“bash”, “-c”, `sed -i -e “s/DRUMCLASS/False/g” “/usr/share/OCTAVA/Rich/HTTP/CLASS” &> /dev/null)`

在Go语言中实现类似sed的文本替换功能,可以使用标准库的io/ioutil(Go 1.16+推荐使用osio包)和strings包。以下是几种实现方式:

方法1:直接文件读取替换(推荐)

package main

import (
    "io/ioutil"
    "log"
    "strings"
)

func main() {
    filePath := "/usr/share/OCTAVA/Rich/HTTP/CLASS"
    
    // 读取文件内容
    content, err := ioutil.ReadFile(filePath)
    if err != nil {
        log.Fatal(err)
    }
    
    // 执行替换操作
    newContent := strings.ReplaceAll(string(content), "DRUMCLASS", "False")
    
    // 写回文件
    err = ioutil.WriteFile(filePath, []byte(newContent), 0644)
    if err != nil {
        log.Fatal(err)
    }
}

方法2:使用正则表达式替换

如果需要更复杂的模式匹配,可以使用regexp包:

package main

import (
    "io/ioutil"
    "log"
    "regexp"
)

func main() {
    filePath := "/usr/share/OCTAVA/Rich/HTTP/CLASS"
    
    content, err := ioutil.ReadFile(filePath)
    if err != nil {
        log.Fatal(err)
    }
    
    // 编译正则表达式
    re := regexp.MustCompile(`DRUMCLASS`)
    
    // 执行替换
    newContent := re.ReplaceAllString(string(content), "False")
    
    err = ioutil.WriteFile(filePath, []byte(newContent), 0644)
    if err != nil {
        log.Fatal(err)
    }
}

方法3:处理大文件的流式替换

对于大文件,可以使用缓冲读写:

package main

import (
    "bufio"
    "io"
    "log"
    "os"
    "strings"
)

func main() {
    filePath := "/usr/share/OCTAVA/Rich/HTTP/CLASS"
    tmpPath := filePath + ".tmp"
    
    // 打开源文件
    srcFile, err := os.Open(filePath)
    if err != nil {
        log.Fatal(err)
    }
    defer srcFile.Close()
    
    // 创建临时文件
    tmpFile, err := os.Create(tmpPath)
    if err != nil {
        log.Fatal(err)
    }
    defer tmpFile.Close()
    
    // 使用缓冲读写器
    scanner := bufio.NewScanner(srcFile)
    writer := bufio.NewWriter(tmpFile)
    
    for scanner.Scan() {
        line := scanner.Text()
        newLine := strings.ReplaceAll(line, "DRUMCLASS", "False")
        writer.WriteString(newLine + "\n")
    }
    
    writer.Flush()
    
    // 检查扫描错误
    if err := scanner.Err(); err != nil {
        log.Fatal(err)
    }
    
    // 关闭文件
    srcFile.Close()
    tmpFile.Close()
    
    // 替换原文件
    err = os.Rename(tmpPath, filePath)
    if err != nil {
        log.Fatal(err)
    }
}

方法4:封装成函数

package main

import (
    "io/ioutil"
    "log"
    "strings"
)

func sedReplace(filePath, oldStr, newStr string) error {
    content, err := ioutil.ReadFile(filePath)
    if err != nil {
        return err
    }
    
    newContent := strings.ReplaceAll(string(content), oldStr, newStr)
    
    return ioutil.WriteFile(filePath, []byte(newContent), 0644)
}

func main() {
    err := sedReplace("/usr/share/OCTAVA/Rich/HTTP/CLASS", "DRUMCLASS", "False")
    if err != nil {
        log.Fatal(err)
    }
}

注意事项

  1. 权限问题:确保Go程序有足够的权限读取和写入目标文件
  2. 错误处理:实际生产代码需要更完善的错误处理
  3. 并发安全:如果文件可能被其他进程访问,需要考虑文件锁
  4. 备份:重要文件操作前建议备份原文件

这些方法都能实现与sed -i -e "s/DRUMCLASS/False/g"相同的功能,其中方法1是最简单直接的实现。

回到顶部