douchibu7040 2018-02-08 21:50
浏览 28
已采纳

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

I am trying to invoke a git log from go and redirect the output to a given file.

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)
}

fails with

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>...]'

Executing the command in bash directly poses no problem.

  • 写回答

1条回答 默认 最新

  • doudg60800 2018-02-08 21:59
    关注

    Go's cmd.Run() acts similarly to the C fork() and exec() process for starting a new program. This doesn't implicitly invoke a shell -- which is, from a security perspective, an extremely good thing; unnecessary shell invocation often leads to command injection vulnerabilities.

    If you want capabilities that a shell can add -- here, redirection and compound command syntax -- but want to avoid the security risks, pass your data out-of-band from code:

    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...)
    

    The above is equivalent to the following shell script:

    #!/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
    

    Note that I removed the literal quotes from inside --pretty=. That's because when you run the command in a shell, those quotes are treated as syntax by the shell -- an instruction not to split on the spaces within the format string. Here, there is no shell parsing that string as code; if we left the quotes in, they would become a literal part of your format string.

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论

报告相同问题?

悬赏问题

  • ¥15 对于知识的学以致用的解释
  • ¥50 三种调度算法报错 有实例
  • ¥15 关于#python#的问题,请各位专家解答!
  • ¥200 询问:python实现大地主题正反算的程序设计,有偿
  • ¥15 smptlib使用465端口发送邮件失败
  • ¥200 总是报错,能帮助用python实现程序实现高斯正反算吗?有偿
  • ¥15 对于squad数据集的基于bert模型的微调
  • ¥15 为什么我运行这个网络会出现以下报错?CRNN神经网络
  • ¥20 steam下载游戏占用内存
  • ¥15 CST保存项目时失败