在Golang中运行awk的方法与实践

在Golang中运行awk的方法与实践 我正在尝试执行这段代码,但只得到错误信息

_, err := exec.Command("awk", '{gsub(/./,",",$0);print $0}', file, "| sponge", file).Output()

你能帮助我吗?

谢谢

16 回复

是的,执行该代码时我遇到了那个错误

更多关于在Golang中运行awk的方法与实践的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


感谢大家的建议,在你们的帮助下我成功解决了问题。

标准错误输出显示什么?很可能就是之前解释过的未知参数问题

"无法工作"具体是什么意思?另外请使用markdown正确格式化你的代码…还有你粘贴的代码中有一些空格,这些是不允许存在的…

_, err := exec.Command("awk", `{gsub(/\./",",$0);print $0}`, file, "| sponge", file).Output()

错误:退出状态 2

糟糕!

我不知道如何在这种情况下应用 stderr

我想要实现的是在一个巨型文件中将“.”替换为“,”,我找到的最快方法是使用 awk,但我无法从 golang 中运行它

epicteto:

但它没有将点替换为逗号

你考虑过使用 tr 吗?tr . ,

// 代码示例
func main() {
    fmt.Println("hello world")
}

检查 Sprintf 调用的结果是否符合你在命令行中输入的形式。

但乍看之下,似乎你其中一条帖子缺少了逗号……我只是从那里复制的。

调试 awk 是你的工作,我不懂这个。

抱歉

output, err := exec.Command("bash", "-c", fmt.Sprintf(`awk '{gsub(/\./",",$0);print $0}' %[1]s | sponge %[1]s`, file)).Output()

它没有报错,但没有将点号替换为逗号,而这正是我希望代码实现的功能

衷心感谢您的帮助。

我执行了:

output, err: = exec.Command (“bash”, “-c”, fmt.Sprintf (`awk '{gsub (/\./",",$ 0); print $ 0}'% [1] s | sponge % [1] s`, fileAnalysis)). Output ()

它没有报错,但并未生效。

以下是我在状态栏应用中使用 awk 的方法:

首先将命令设置为字符串变量:

homeCmd := "df -Ph .| awk '/d*G/ {print $4}'"

然后在调用命令时需要通过 sh -c 来运行(在我的案例中还会捕获输出):

homeOut, err := exec.Command("sh", "-c", homeCmd).Output()

希望这能帮助阐明这个问题!

什么错误?

是因为错误使用 ' 导致的语法错误?还是因为 awk 无法将 | sponge 识别为参数?

exec.Command() 会绕过你的 shell 直接启动程序,你需要手动在 awksponge 之间建立管道。

另外 ' 用于字符而非字符串,你需要使用 " 并对内部引号进行转义,或者使用反引号包围的原始字符串(`{gsub(/./,",",$0);print $0}`)。

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

不妨先来看看显而易见的解决方案

/tmp % echo "Here. Is. A file." > foo
/tmp % sed -i.bak -e 's/\./,/g' foo
/tmp % cat foo
Here, Is, A file,

但如果你必须使用Go语言并且必须使用awk,关于你消失的逗号问题,NobbZ的说法是正确的。

你原来的代码是:

awk '{gsub(/\./",",$0);print $0}' %[1]s | sponge %[1]s

我通过在正则表达式/\./后面添加逗号获得了成功:

awk '{gsub(/\./, ",",$0);print $0}' %[1]s | sponge %[1]s

最简单的方法是使用 exec.(*Cmd).CombinedOutput(),至少在目前的情况下,这是侵入性最小的修复方案。

output, err := exec.Command(“awk”, `{gsub(/\./",",$0);print $0}`, file, “| sponge”, file).CombinedOutput()
fmt.Println(string(output))
fmt.Println(err)

结果可能会是这样:

# Created by newuser for 5.7.1
awk: cmd. line:1: fatal: cannot open file `| sponge' for reading (No such file or directory)

因为您运行的命令相当于在bash中执行以下命令:

awk '{gsub(/\./",",$0);print $0}' ~/.zshrc "| sponge" ~/.zshrc

你需要手动管理 *Cmd 的生命周期,并使用 exec.(*Cmd).Run()exec.(*Cmd).StdoutPine()exec.(*Cmd).StdinPipe()awkstdoutspongestdin 手动连接起来。

我实际上从未这样做过。

或者,你可以启动 bash 并执行类似以下操作:

output, err := exec.Command(bash, "-c", fmt.Sprintf(`awk '{gsub(/\./",",$0);print $0}' %[1]s | sponge %[1]s`, file)),Output()

不过我建议不要丢弃 stderr,而是使用 Run() 并准备附加到 stderr/stdout 的缓冲区,以确保在出现错误时能够显示输出,这样会更容易进行调试…

在你的代码中,有几个问题需要修正。主要问题是管道符号 |sponge 命令的使用方式不正确。exec.Command 不能直接处理管道操作符,因为这是 shell 的功能。以下是几种可行的解决方案:

方案1:使用shell执行命令

通过 /bin/sh/bin/bash 来执行包含管道的完整命令:

cmd := exec.Command("/bin/sh", "-c", fmt.Sprintf("awk '{gsub(/./,\",\",$0);print $0}' %s | sponge %s", file, file))
output, err := cmd.Output()
if err != nil {
    log.Fatal(err)
}
fmt.Printf("Output: %s\n", output)

方案2:分别执行awk和sponge,并通过Go管理管道

手动创建管道连接两个命令:

// 创建awk命令
awkCmd := exec.Command("awk", "{gsub(/./,\",\",$0);print $0}", file)

// 创建sponge命令
spongeCmd := exec.Command("sponge", file)

// 创建管道
pipeReader, pipeWriter := io.Pipe()
awkCmd.Stdout = pipeWriter
spongeCmd.Stdin = pipeReader

// 启动命令
if err := awkCmd.Start(); err != nil {
    log.Fatal(err)
}
if err := spongeCmd.Start(); err != nil {
    log.Fatal(err)
}

// 等待命令完成
if err := awkCmd.Wait(); err != nil {
    log.Fatal(err)
}
pipeWriter.Close()
if err := spongeCmd.Wait(); err != nil {
    log.Fatal(err)
}

方案3:纯Go实现(推荐)

如果可能,考虑使用Go原生字符串处理替代awk,避免外部命令依赖:

content, err := os.ReadFile(file)
if err != nil {
    log.Fatal(err)
}

// 将每个字符替换为逗号
result := strings.ReplaceAll(string(content), "", ",")
// 移除开头多余的逗号(如果不需要)
result = strings.TrimPrefix(result, ",")

err = os.WriteFile(file, []byte(result), 0644)
if err != nil {
    log.Fatal(err)
}

注意事项:

  1. 确保系统中已安装 sponge 命令(通常来自 moreutils 包)
  2. 方案1最简单,但依赖shell环境
  3. 方案2更可控,但代码较复杂
  4. 方案3性能最好,且不依赖外部工具

根据你的具体需求选择合适的方法。如果只是简单的字符串替换,方案3是最佳选择。

回到顶部