I'm trying to convert exec output to json format. I just want to read a single string from the output, what would be the right way to do it. I thought about jq also but didn't work for me.
Here is the code snippet:
package main
import (
"fmt"
"encoding/json"
"os/exec"
)
type pkg struct {
Package string `json:"package"`
Version string `json:"version:"`
}
func main() {
fmt.Println("Hello, 世界")
cmd := exec.Command("dpkg", "-s", "tar")
output, err := cmd.CombinedOutput()
if err != nil {
fmt.Printf("%v", err)
}
var xyz pkg
if err := json.Unmarshal([]byte(output), &xyz); err != nil {
fmt.Printf("\n%v %v\n", string(output), err)
}
fmt.Println(xyz)
}
Command output:
$ dpkg -s tar
Package: tar
Essential: yes
Status: install ok installed
Priority: required
Section: utils
Installed-Size: 3152
Maintainer: Janos Lenart <ocsi#debian.org>
Architecture: amd64
Multi-Arch: foreign
Version: 1.34+dfsg-1
Replaces: cpio (<< 2.4.2-39)
Pre-Depends: libacl1 (>= 2.2.23), libc6 (>= 2.28), libselinux1 (>= 3.1~)
Suggests: bzip2, ncompress, xz-utils, tar-scripts, tar-doc
Breaks: dpkg-dev (<< 1.14.26)
Conflicts: cpio (<= 2.4.2-38)
Description: GNU version of the tar archiving utility
Tar is a program for packaging a set of files as a single archive in tar
format. The function it performs is conceptually similar to cpio, and to
things like PKZIP in the DOS world. It is heavily used by the Debian package
management system, and is useful for performing system backups and exchanging
sets of files with others.
Homepage: https://www.gnu.org/software/tar/
I'm getting the following error on json.Unmarshal:
invalid character 'P' looking for beginning of value
A simple solution could be use dpkg-query to format your desired output in json format:
package main
import (
"fmt"
"encoding/json"
"os/exec"
)
type pkg struct {
Package string `json:"package"`
Version string `json:"version"`
}
func main() {
cmd := exec.Command("dpkg-query", "-W", "-f={ \"package\": \"${Package}\", \"version\": \"${Version}\" }", "tar")
output, err := cmd.CombinedOutput()
if err != nil {
fmt.Printf("%v", err)
}
fmt.Println(string(output))
var xyz pkg
if err := json.Unmarshal([]byte(output), &xyz); err != nil {
fmt.Printf("\n%v %v\n", string(output), err)
}
fmt.Println(xyz.Package)
fmt.Println(xyz.Version)
}
{ "package": "tar", "version": "1.34+dfsg-1" }
tar
1.34+dfsg-1
Related
As the title says, I have an error when importing go-mysql-driver package. I have installed the go-my-sql driver in my machine but the error still persists. I use XAMPP for local hosting and here’s the block of program.
package model
import (
"database/sql"
"fmt"
_ "github.com/go-sql-driver/mysql"
)
type Table interface {
Name() string
Field() ([]string, []interface{})
}
func Connect(username string, password string, host string, database string) (*sql.DB, error) {
conn := fmt.Sprintf("%s:%s#tcp(%s:3306)/%s", username, password, host, database)
db, err := sql.Open("mysql", conn)
return db, err
}
func CreateDB(db *sql.DB, name string) error {
query := fmt.Sprintf("CREATE DATABASE %v", name)
_, err := db.Exec(query)
return err
}
func CreateTable(db *sql.DB, query string) error {
_, err := db.Exec(query)
return err
}
func DropDB(db *sql.DB, name string) error {
query := fmt.Sprintf("DROP DATABASE %v", name)
_, err := db.Exec(query)
return err
}
could not import github.com/go-sql-driver/mysql (no required modules provides package "github.com/go-sql-driver/mysql")
screenshot of what's happening
It seems that you read the tutorial for an older go version.
Go 1.17 requires dependencies must be explicitly in go.mod.
Maybe you could try go module first (https://go.dev/blog/using-go-modules)
Your IDE is not showing you the whole picture. By running go run main.go (or whatever main file you have) on the command line, you can see the same error as you're seeing on your IDE with some extra:
$ go run main.go
main.go:7:5: no required module provides package github.com/go-sql-driver/mysql; to add it:
go get github.com/go-sql-driver/mysql
By issuing the suggested command go get github.com/go-sql-driver/mysql, you'll get the dependency added to your go.mod file and the contents of the package will be downloaded to your machine.
Your next execution will work:
$ go run main.go
Hello world
I've made some small modifications to your code to work, I'll add them here for completeness:
I've used the same source, but changed the package name to main.
I've added a main function to the bottom of the file:
func main() {
fmt.Println("Hello world")
_, err := Connect("username", "password", "localhost", "db")
if err != nil {
panic(err)
}
}
I've saved to a file named main.go
I've initialized the go.mod file by running go mod init test and go mod tidy, then I took the steps described on the beginning of the answer.
I installed the libs and can run/debug the libvirt related codes in idea IDE, but after running below build command on MacBook
CGO_ENABLED=0 GOOS=windows GOARCH=amd64 go build -o zagent.exe cmd/test/main.go
I got
cmd/test/main.go:11:22: undefined: libvirt.NewConnect
Thank you for your attention, below is the codes:
package main
import (
_logUtils "github.com/easysoft/zagent/internal/pkg/lib/log"
"github.com/libvirt/libvirt-go"
)
func main() {
connStr := "***"
LibvirtConn, err := libvirt.NewConnect(connStr)
if err != nil {
_logUtils.Errorf(err.Error())
return
}
active, err := LibvirtConn.IsAlive()
if err != nil {
_logUtils.Errorf(err.Error())
return
}
if !active {
_logUtils.Errorf("not active")
}
}
The libvirt-go package is a CGo based API to the underlying libvirt.so library. You cannot set CGO_ENABLED=0 and expect it to still work. AFAI, Go toolchain doesn't allow cross-compiling with CGo either.
Although the output setting has been set to text
~/.aws/config
[default]
output=text
the aws-sdk-go returns json. The question is whether the output could be switched to text.
When:
aws route53 get-hosted-zone --id some-id
is run, the output looks as follows:
NAMESERVERS some-ns
NAMESERVERS some-ns1
NAMESERVERS some-ns2
NAMESERVERS some-ns3
According to the this AWS documentation one could set the configuration:
sess, err := session.NewSession(&aws.Config{
Region: aws.String("us-east-2")},
)
One attempt was to consult this Config struct, but an Output option seems to be omitted.
How to set the output to text?
Note: an issue has added to the github page of the aws-sdk-go as well.
Example
package main
import (
"fmt"
"log"
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/aws/session"
"github.com/aws/aws-sdk-go/service/route53"
)
func main() {
session, err := session.NewSession()
if err != nil {
log.Fatal(err)
}
r53 := route53.New(session)
listParams := &route53.ListResourceRecordSetsInput{
HostedZoneId: aws.String("some-id"),
}
records, err := r53.ListResourceRecordSets(listParams)
if err != nil {
log.Fatal(err)
}
fmt.Println(records)
}
returns:
{
IsTruncated: false,
MaxItems: "100",
ResourceRecordSets: [
{
Name: "some-domain.",
ResourceRecords: [{
Value: "some-ip"
}],
TTL: 7200,
Type: "A"
}
}
while aws route53 list-resource-record-sets --hosted-zone-id some-id, results in:
RESOURCERECORDSETS some-domain. 7200 A
RESOURCERECORDS some-ip
Problem
While it is possible to set the format of the aws-cli to output, it does not seem to be possible to do the same for the SDK.
Question
How to let the go-aws-sdk return text rather than json?
I have all of the information you need, you just have to unravel it from the response (records).
To get similar results from the last cli command:
for _, recordSet := range records.ResourceRecordSets {
log.Println("RESOURCERECORDSETS " + *recordSet.Name + strconv.Itoa(int(*recordSet.TTL)) + *recordSet.Type)
for _, record := range recordSet.ResourceRecords {
log.Println("RESOURCERECORDS " + *record.Value)
}
log.Println("")
}
When decoding a timestamp field from JSON into a struct on my local OS X machine, the Location of the time.Time field is "empty" rather than UTC. This is problematic for me running unit tests locally (vs. on a CI server where the Location is being set correctly to be UTC).
Here's the example code: https://play.golang.org/p/pb3eMbjSmv
package main
import (
"fmt"
"time"
)
func main() {
// Ignoring the err just for this example's sake!
parsed, _ := time.Parse(time.RFC3339, "2017-08-15T22:30:00+00:00")
fmt.Printf("String(): %v\n", parsed.String())
fmt.Printf("Location(): %v\n", parsed.Location())
}
which outputs
String(): 2017-08-15 22:30:00 +0000 +0000
Location():
So while the offset of the time.Time's Location appears to be correct, its timezone name is just an empty string. Running in on other machines (and The Go Playground) give the expected "UTC" location.
When I run that on my machine, I see
TimeField.String(): 2017-08-15 22:30:00 +0000 +0000
TimeField.Location():
So while the offset of the time.Time's Location appears to be correct, its timezone name is just an empty string. This is using Go 1.5:
go version go1.5 darwin/amd64
I find same behavior using my current setup on Mac and I suspect it will be same behavior on Linux (not sure through)
$ go version
go version devel +31ad583 Wed Aug 10 19:44:08 2016 +0000 darwin/amd64
To make it more deterministic, I suggest using a custom json Unmarshal like so:
package main
import (
"encoding/json"
"fmt"
"strings"
"time"
)
type Time struct {
*time.Time
}
func (t *Time) UnmarshalJSON(b []byte) error {
const format = "\"2006-01-02T15:04:05+00:00\""
t_, err := time.Parse(format, string(b))
if err != nil {
return err
}
*t = Time{&t_}
return nil
}
type Example struct {
TimeField *Time `json:"time_field"`
}
func main() {
inString := "{\"time_field\": \"2017-08-15T22:30:00+00:00\"}"
var ex Example
decoder := json.NewDecoder(strings.NewReader(inString))
decoder.Decode(&ex)
fmt.Printf("TimeField.String(): %v\n", ex.TimeField.String())
fmt.Printf("TimeField.Location(): %v\n", ex.TimeField.Location())
}
Yes, You are right. On The Go Playground the Local is set to UTC inside that sandbox:
Try this working sample code on The Go Playground:
package main
import (
"fmt"
"runtime"
"time"
)
func main() {
fmt.Println(runtime.Version(), runtime.GOARCH, runtime.GOOS) //go1.7 amd64p32 nacl
parsed, err := time.Parse(time.RFC3339, "2017-08-15T22:30:00+00:00")
if err != nil {
panic(err)
}
fmt.Printf("String(): %v\n", parsed.String())
fmt.Printf("Location(): %v\n", parsed.Location())
}
output on The Go Playground:
go1.7 amd64p32 nacl
String(): 2017-08-15 22:30:00 +0000 UTC
Location(): UTC
And try it on your local system, output Location() is empty.
You may use utc := parsed.UTC() with the location set to UTC, like this working sample code The Go Playground:
package main
import (
"fmt"
"runtime"
"time"
)
func main() {
fmt.Println(runtime.Version(), runtime.GOARCH, runtime.GOOS) //go1.7 amd64p32 nacl
parsed, err := time.Parse(time.RFC3339, "2017-08-15T22:30:00+00:00")
if err != nil {
panic(err)
}
fmt.Printf("String(): %v\n", parsed.String())
fmt.Printf("Location(): %v\n", parsed.Location())
utc := parsed.UTC()
fmt.Printf("String(): %v\n", utc.String())
fmt.Printf("Location(): %v\n", utc.Location())
}
Also You may use time.ParseInLocation(time.RFC3339, "2017-08-15T22:30:00+00:00", time.UTC), like this working sample code:
package main
import (
"fmt"
"runtime"
"time"
)
func main() {
fmt.Println(runtime.Version(), runtime.GOARCH, runtime.GOOS) //go1.7 amd64p32 nacl
parsed, err := time.ParseInLocation(time.RFC3339, "2017-08-15T22:30:00+00:00", time.UTC)
if err != nil {
panic(err)
}
fmt.Printf("String(): %v\n", parsed.String())
fmt.Printf("Location(): %v\n", parsed.Location())
}
So the Location() will be UTC.
Thanks to #djd for pointing out that we can skip all the JSON/struct decoding business; the key issue is with time.Parse.
The same issue comes up here where the Location is "empty" rather than UTC (I would've expected UTC based on the docs: https://golang.org/pkg/time/#Parse
In the absence of a time zone indicator, Parse returns a time in UTC.
This answer was taken from the question as of revision 6.
I am using the following sample program:
func getEnv(appName string, env string) {
svc := elasticbeanstalk.New(session.New(), &aws.Config{Region: aws.String("us-east-1")})
params := &elasticbeanstalk.DescribeConfigurationSettingsInput{
ApplicationName: aws.String(appName), // Required
EnvironmentName: aws.String(env),
}
resp, err := svc.DescribeConfigurationSettings(params)
if err != nil {
fmt.Println(err.Error())
return
}
v := resp.ConfigurationSettings
fmt.Printf("%s", v)
}
It's printing out the following response; this looks like a valid json except for the missing quote makes. ex: ApplicationName and not "ApplicationName".
How do I parse this? or get a valid json from AWS?
ConfigurationSettings: [{
ApplicationName: "myApp",
DateCreated: 2016-01-12 00:10:10 +0000 UTC,
DateUpdated: 2016-01-12 00:10:10 +0000 UTC,
DeploymentStatus: "deployed",
Description: "Environment created from the EB CLI using \"eb create\"",
EnvironmentName: "stag-myApp-app-s1",
OptionSettings: [
...
resp.ConfigurationSettings is not in JSON format any more, the aws-sdk-go package handled that for you. When you do,
v := resp.ConfigurationSettings
v contains an instance []*ConfigurationSettingsDescription that was parsed from the JSON response, and you don't have to parse it yourself. What you are seeing when you print it out is the Go struct representation. You can just go ahead and use it:
if len(v) > 0 {
log.Println(v[0].ApplicationName)
}
This should print out myApp