我正在用 go 编写一个 bash 任务运行程序,它有一个简单的概念:
taskfile
,这是一个包含任务定义(简单的 bash 函数声明)的 bash 脚本这是一个简化的示例:
package main import ( "fmt" "os/exec" ) func main() { //simplified for a dynamically built script taskfilecontent := "#!/bin/bash\n\ntask:foo (){\n echo \"test\"\n}\n" // simplified for passed arguments task := "\ntask:foo" bash, _ := exec.lookpath("bash") cmd := exec.command(bash, "-c", "\"$(cat << eof\n"+taskfilecontent+task+"\neof\n)\"") fmt.println(cmd.string()) out, _ := cmd.combinedoutput() fmt.println(string(out)) }
我现在的问题是,如果通过 go 执行它就不起作用,并且我收到此错误
task:foo: no such file or directory
但是如果我直接在 shell 中执行生成的脚本,它确实有效:
$ /opt/opt/homebrew/bin/bash -c "$(cat << EOF #!/bin/bash task:foo (){ echo "test" } task:foo EOF )" test <-- printed out from the `task:foo` above
我在这里做错了什么?
你不会得到任何你不会得到的东西:
cmd := exec.command(bash, "-c", taskfilecontent+"\n"+task)
如果省略它,您的代码会更简单。
当您在 shell 中运行时:
65be85239床5...围绕 $()
的 "
s 不是正在启动的 bash 副本的语法,而是正在解析命令的 bash 副本的语法。 /em>。它们告诉 bash 的副本,命令替换的结果将作为一个字符串传递,不受字符串分割或通配符的影响。
类似地, $(cat <<eof
、eof
和最终的 )"
也是交互式 shell 的指令,而不是它调用的非交互式 shell。它是运行的交互式 shell cat
(包含连接到其标准输入的heredoc内容的临时文件),读取 cat
副本的标准输出,然后将该数据替换为传递给 bash -c
的单个参数。
在您的 go 程序中,您没有交互式 shell,因此您应该使用 go 语法(而不是 shell 语法)来执行所有这些步骤。就这些步骤而言,没有理由在转到第一个位置(没有必要将数据文件写入临时文件,没有必要让 /bin/cat
读取该文件的内容,没有必要使用子进程运行命令替换来生成一个字符串(由这些内容组成),然后将其放在最终 shell 的命令行中),因此忽略所有这些步骤会更明智。
以上がGo を使用して、1 行の関数宣言を含む動的 bash スクリプトを実行するの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。