英文:
Echo text to a file in golang
问题
在Golang中,可以使用类似下面的bash代码的方式进行操作:
package main
import (
"fmt"
"io/ioutil"
"os"
)
func GrafanaProvData() {
data := `apiVersion: 1
deleteDatasources:
- name: Clickhouse
orgId: 1
datasources:
- name: Clickhouse
type: vertamedia-clickhouse-datasource
access: proxy
url: http://localhost:8123
basicAuth: 1
basicAuthUser: default
basicAuthPassword: $password
isDefault: false
defaultDatabase:`
err := ioutil.WriteFile("/etc/grafana/provisioning/datasources/datasource.yml", []byte(data), os.ModePerm)
if err != nil {
fmt.Println("Error:", err)
return
}
fmt.Println("File written successfully")
}
func main() {
GrafanaProvData()
}
这段代码将数据写入到/etc/grafana/provisioning/datasources/datasource.yml
文件中。你可以根据需要修改数据内容。
英文:
Is it possible to do something in Golang similar to the below in bash
GrafanaProvData()
{
cat > /etc/grafana/provisioning/datasources/datasource.yml << EOF
apiVersion: 1
deleteDatasources:
- name: Clickhouse
orgId: 1
datasources:
- name: Clickhouse
type: vertamedia-clickhouse-datasource
access: proxy
url: http://localhost:8123
basicAuth: 1
basicAuthUser: default
basicAuthPassword: $password
isDefault: false
defaultDatabase:
EOF
}
i have tried command.exec but its not exactly what is needed
答案1
得分: 3
这个shell脚本的作用是使用所谓的“here document”(在链接中有详细介绍)来将shell的标准输入管道传递给命令cat
,而cat
命令的标准输出则被重定向到一个文件中。通过使用>
进行重定向,文件要么被创建,要么被截断。
正如一些人评论的那样,在Go语言中,这基本上等同于将一个字符串字面量写入文本文件。
但请注意,有一个细节:当shell处理here-document时,它会在实际使用之前对文档的文本进行各种扩展,包括变量扩展,除非采取特殊的措施来阻止扩展。因此,在你的示例中,变量“password”的内容将替换$password
的位置。
考虑到这一点,你可以这样做:
const tmpl = `apiVersion: 1
deleteDatasources:
- name: Clickhouse
orgId: 1
datasources:
- name: Clickhouse
type: vertamedia-clickhouse-datasource
access: proxy
url: http://localhost:8123
basicAuth: 1
basicAuthUser: default
basicAuthPassword: %s
isDefault: false
defaultDatabase:
`
fd, err := os.OpenFile("/etc/grafana/provisioning/datasources/datasource.yml",
os.O_WRONLY|os.O_TRUNC, 0666)
if err != nil {
log.Fatal(err)
}
defer fd.Close()
_, err := fmt.Fprintf(tmpl, password)
if err != nil {
log.Fatal(err)
}
另外,还有两点需要考虑:
- 如果模板变得更加复杂,使用
fmt.*f
系列函数来完成任务会变得越来越困难;这时你可能需要查看text/template
标准包。 - 如果你需要对YAML模板进行更高级的处理,可能更方便的做法是停止使用格式无关的方法,而是使用Go中的任何YAML处理包,比如古老的
gopkg.in/yaml.v3
,首先填充一个自定义复合类型的变量,然后将其编组为一个YAML格式的文档。这样可以避免某些奇怪的错误(考虑一下:如果你的密码包含会被YAML解析器解释为合法YAML语法的字符,会发生什么?一个“真正”的YAML编组器会转义任何可能被错误解释的内容,而任何“模板化”方法则不会)。
还有一个提示:当要写入的文件很大(比如超过10k)时,将bufio.Writer
放在fmt.Fprint*
函数和打开的文件之间可能是值得的,以优化文件系统访问。
英文:
What happens in this shell script is the usage of the so-called "here document" which is piped by the shell to the standard input of the command cat
whose standard output is directed to a file, which — due to the redirection set up using >
— will be either created or truncated.
As commented by some folks, in Go, that would mostly amount to writing a string literal to a text file.
But note that there is a twist: when here-documents are processed by the shell it performs various expansions — including variable expansion — in the document's text before actually using it — unless special action is taken to prevent that.
So, in your example, the contents of the variable "password" would be substituted in place of $password
.
With this in mind, what you'd do is something like
const tmpl = `apiVersion: 1
deleteDatasources:
- name: Clickhouse
orgId: 1
datasources:
- name: Clickhouse
type: vertamedia-clickhouse-datasource
access: proxy
url: http://localhost:8123
basicAuth: 1
basicAuthUser: default
basicAuthPassword: %s
isDefault: false
defaultDatabase:
`
fd, err := os.OpenFile("/etc/grafana/provisioning/datasources/datasource.yml",
os.O_WRONLY|os.O_TRUNC, 0666)
if err != nil {
log.Fatal(err)
}
defer fd.Close()
_, err := fmt.Fprintf(tmpl, password)
if err != nil {
log.Fatal(err)
}
While we are at it, consider two more things:
- If/when the template becomes more complicated, it would become progressively harder to use the functions of the
fmt.*f
family to cut the task; you then might want to look at thetext/template
standard package. - If/when you would need even more advanced processing of your YAML templates, it might be more convenient to stop being format-agnostic and use any YAML-handling package for Go — such as the venerable
gopkg.in/yaml.v3
to first fill a variable of some custom compound type and then marshal it as a YAML-formatted document.
This might help prevent a certain class of weird erorrs (consider: what happens if your password contains letters which will be interpreted by a YAML parser as a proper YAML syntax? A "real" YAML marshaler would escape anything which would be improperly interpreted — while any "templating" approach would not.)
One more hint: when the file to be written is big (like, over 10k), it might be worthwhile to stick a bufio.Writer
between the fmt.Fprint*
functions and the opened file—to optimize filesystem access.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论