gpt4 book ai didi

go - exec git 命令拒绝重定向到 Go 中的文件

转载 作者:数据小太阳 更新时间:2023-10-29 03:44:25 27 4
gpt4 key购买 nike

我正在尝试从 go 调用 git 日志并将输出重定向到给定文件。

cmdArgs = []string{"log", "--numstat", "--reverse", fmt.Sprintf("%s..HEAD", "89c98f5ec48c8ac383ea9e27d792c3dc77fa6240"), `--pretty="format:=%P %H %an %ae %ad %at %s %b"`}

cmdArgs = append(cmdArgs, ">> "+workingDir+"/logs/"+repoName+".log && cat "+workingDir+"/logs/"+repoName+".log")

cmd := exec.Command("git", cmdArgs...)
cmd.Dir = workingDir + repoName

var out bytes.Buffer
var stderr bytes.Buffer
cmd.Stdout = &out
cmd.Stderr = &stderr
err := cmd.Run()
if err != nil {
fmt.Println("git", strings.Join(cmdArgs, " "), "in", workingDir+repoName)
fmt.Println(fmt.Sprint(err) + ": " + stderr.String())
panic(err)
}

失败了

git log --numstat --reverse --pretty="format:=%P %H %an %ae %ad %at %s %b" 89c98f5ec48c8ac383ea9e27d792c3dc77fa6240..HEAD  > /someplace/xx-tmp.log && cat /someplace/xx-tmp.log in /someplace
exit status 128: fatal: ambiguous argument ' > /someplace/xx-tmp.log && cat /someplace/xx-tmp.log: unknown revision or path not in the working tree.
Use '--' to separate paths from revisions, like this:
'git <command> [<revision>...] -- [<file>...]'

直接在bash中执行命令没有问题。

最佳答案

Go 的 cmd.Run() 与 C fork()exec() 启动新程序的过程类似。这不会隐式调用 shell —— 从安全的角度来看,这是一件非常好的事情;不必要的 shell 调用通常会导致命令注入(inject)漏洞。

如果您想要 shell 可以添加的功能——这里是重定向和复合命令语法——但又想避免安全风险,请从代码带外传递数据:

cmdArgs = []string{
"-c", // tells interpreter that script is next argument
`outfile=$1; shift; "$@" >"$outfile" && cat "$outfile"`, // script to execute
"_", // this is $0
workingDir+"/logs/"+repoName+".log", // $1, becomes outfile
"git", "log", "--numstat", "--reverse", // remaining args are in "$@"
fmt.Sprintf("%s..HEAD", "89c98f5ec48c8ac383ea9e27d792c3dc77fa6240"),
"--pretty=format:=%P %H %an %ae %ad %at %s %b"
}

cmd := exec.Command("sh", cmdArgs...)

以上相当于下面的shell脚本:

#!/bin/sh
# ^^- not /bin/bash; this only guarantees support for POSIX syntax

outfile=$1 # assign first positional argument to variable "$outfile"
shift # rename $2 to $1, $3 to $2, etc
if "$@" >"$outfile"; then # run remaining arguments as a single command, stdout to outfile
cat "$outfile" # if that succeeded, then cat our "$outfile" to stdout
fi

请注意,我从 --pretty= 中删除了文字引号。这是因为当您在 shell 中运行该命令时,这些引号被 shell 视为语法 —— 一条不在格式字符串中的空格处拆分的指令。在这里,没有 shell 将该字符串解析为代码;如果我们保留引号,它们将成为格式字符串的文字部分。


综上所述,没有充分的理由为此使用 shell。你可以在原生 Go 中简单地进行重定向:

cmdArgs = []string{
"log", "--numstat", "--reverse",
fmt.Sprintf("%s..HEAD", "89c98f5ec48c8ac383ea9e27d792c3dc77fa6240"),
`--pretty=format:=%P %H %an %ae %ad %at %s %b`}
cmd := exec.Command("git", cmdArgs...)
cmd.Dir = workingDir + repoName

outputFile, err = os.OpenFile(workingDir+"/logs/"+repoName+".log",
os.O_APPEND | os.O_CREATE | os.O_WRONLY, 0644)
if err != nil { panic(err) }
defer outputFile.Close()

cmd.Stdout = outputFile

...然后将 cat 作为单独的 exec.Command 实例运行(如果您有充分的理由不只在原生 Go 中实现它)。

关于go - exec git 命令拒绝重定向到 Go 中的文件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48695341/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com