How do I read string argument include & in Go for example this link
$ ./main
https://www.youtube.com/watch?v=G3PvTWRIhZA&list=PLQVvvaa0QuDeF3hP0wQoSxpkqgRcgxMqX
without use double quotation (")
$ ./main
"https://www.youtube.com/watch?v=G3PvTWRIhZA&list=PLQVvvaa0QuDeF3hP0wQoSxpkqgRcgxMqX"
main.go
package main
import (
"os"
"fmt"
)
func main() {
link := os.Args[1]
fmt.Println(link)
}
$ go build main.go
$ ./main
https://www.youtube.com/watch?v=G3PvTWRIhZA&list=PLQVvvaa0QuDeF3hP0wQoSxpkqgRcgxMqX
output will be
https://www.youtube.com/watch?v=G3PvTWRIhZA
Both #JimB and #Adrian are correct, the & needs to be escaped.
If you absolutely must find a workaround, you could opt to not use a command-line argument and rather read input instead to bypass need for escaping.
Example:
package main
import (
"fmt"
)
func main() {
var input string
fmt.Scan(&input)
fmt.Println(input)
}
input:
$ ./main
https://www.youtube.com/watch?v=G3PvTWRIhZA&list=PLQVvvaa0QuDeF3hP0wQoSxpkqgRcgxMqX
output:
https://www.youtube.com/watch?v=G3PvTWRIhZA&list=PLQVvvaa0QuDeF3hP0wQoSxpkqgRcgxMqX
Related
In the following directory structure,
.
├── foo.go
├── go.mod
└── main.go
I have a foo.go with a simple type definition:
package main
type Foo struct {
Baz string
}
If I run gofmt -r from the command line to replace a variable name, it works:
> gofmt -r 'Foo -> Bar' foo.go
package main
type Bar struct {
Baz string
}
However, if I try to do this from main.go with the program
package main
import (
"fmt"
"log"
"os/exec"
)
func main() {
combinedOutput, err := exec.Command("gofmt", "-r", "'Foo -> Bar'", "foo.go").CombinedOutput()
if err != nil {
log.Fatalf("gofmt foo.go: %v. Combined output: %s", err, combinedOutput)
}
fmt.Println(string(combinedOutput))
}
I get an error:
> go run main.go
2023/01/14 23:42:07 gofmt foo.go: exit status 2. Combined output: parsing pattern 'Foo at 1:1: rune literal not terminated
exit status 1
Any idea what is causing this?
You don't need to quote arguments to exec.Command; quoting is a feature of your shell, and doesn't apply when you make system calls. It's also not necessary, because quoting is done to delineate arguments in the shell, but in exec.Command, the arguments are separated as arguments to the function call.
Concretely:
exec.Command("gofmt", "-r", "'Foo -> Bar'", "foo.go")
should be
exec.Command("gofmt", "-r", "Foo -> Bar", "foo.go")
Golang's flag package reads the command line flags and args properly if the input provided is of the form : go run main.go -o filename.txt arg1 arg2
But if I try to provide the input like : go run main.go arg1 arg2 -o filename.txt, everything after main.go is read as arguments.
How to make this style work?
My program:
package main
import (
"flag"
"fmt"
)
func main() {
var output string
flag.StringVar(&output, "o", "", "Writes output to the file specified")
flag.Parse()
fmt.Println("Positional Args : ", flag.Args())
fmt.Println("Flag -o : ", output)
}
go run main.go -o filename.txt arg1 arg2
Output:
Positional Args : [arg1 arg2]
Flag -o : filename.txt
go run main.go arg1 arg2 -o filename.txt
Output:
Positional Args : [arg1 arg2 -o filename.txt]
Flag -o :
If you shimmy around with the contents of os.Args, it is possible to accept arg1 arg2 -o filename.txt
Go through the os.Args that is passed in from the command line in the for loop
If a - is seen then set a condition that indicates the first flag has been seen
If the condition is set then populate the "notargs" list. Otherwise, populate the "args" list
There is a bit of extra complication here as the args list that is used to set os.Args to the values that will do the flag processing must include the program name (the original os.Arg[0]) as the first value
This solution does not work with -o filename.txt arg1 arg2
package main
import (
"flag"
"fmt"
"os"
)
func main() {
var output string
var args[]string
var notargs[]string
var in_flags bool=false
for i:=0; i<len(os.Args); i++ {
if os.Args[i][0]=='-' {
in_flags=true
}
if i==0 || in_flags {
notargs=append(notargs,os.Args[i])
} else {
args=append(args,os.Args[i])
}
}
os.Args=notargs
flag.StringVar(&output, "o", "", "Writes output to the file specified")
flag.Parse()
fmt.Println("args ",args)
fmt.Println("Flag -o : ", output)
}
I want to create a simple program using Go that can get an output in the terminal output. For example:
echo "john" | goprogram
The output is hi john
When using command cat
cat list_name.txt | goprogram
The output using
hi doe
hi james
hi chris
Is there a way to do this using Go?
Read from os.Stdin. Here's an example implementation of the Hi program.
package main
import (
"bufio"
"fmt"
"log"
"os"
)
func main() {
s := bufio.NewScanner(os.Stdin)
for s.Scan() {
fmt.Println("hi", s.Text())
}
if s.Err() != nil {
log.Fatal(s.Err())
}
}
This program creates a scanner to read os.Stdin by line. For each line in stdin, the program prints "hi" and the line.
As per the golang documentation, go does not make a call to the system's shell when you are using exec.Command().
From the golang.org documentation on the "os/exec" package:
Unlike the "system" library call from C and other languages, the os/exec package intentionally does not invoke the system shell and does not expand any glob patterns or handle other expansions, pipelines, or redirections typically done by shells.
This presents a problem. Because of this design choice you cannot use piping when executing a command. Therefore the following code does not execute as desired.
package main
import (
"fmt"
"os/exec"
)
func main() {
exec.Command("echo", "Hello", ">>", "~/thing").Run()
cmdOut, _ := exec.Command("cat", "~/thing").Output()
fmt.Println(cmdOut)
}
Instead of printing out the contents of a file that should contain the word 'Hello,' it instead prints out a blank newline. I have tried directly invoking bash like this:
package main
import (
"fmt"
"os/exec"
)
func main() {
exec.Command("bash", "-c", "echo", "Hello", ">>", "~/thing").Run()
cmdOut, _ := exec.Command("cat", "~/thing").Output()
fmt.Println(cmdOut)
}
This, however, produces the same result as the original code. How can I directly invoke the system shell when using golang?
The second argument should be one string. In shell command you need to pass it as one string too. Also ~ is interpreted by bash. You can safely assume that sh exists. Bash shell is not a must.
package main
import (
"fmt"
"os/exec"
)
func main() {
exec.Command("sh", "-c", "echo Hello >> ~/thing").Run()
cmdOut, _ := exec.Command("sh", "-c", "cat ~/thing").Output()
fmt.Println(cmdOut)
}
I'm passing argument from console. There are some flags too. Like:
go run test.go "-IP=10.10.10.10" "-db=kite" "-wv=45" "-cv=75" "A = value1" "B = value2" "C = 100" "D := ((A-B)/A)*C" "D ?"
Here, -IP, -db, -wv, -wc these four are flags and others are passing as normal argument as I know.
Number of flags can be variable.
How can I know how many flags are passed to my program. In this case 4 flags are passed.
If you use the standard flag package to parse command-line flags, you can call the NFlag function to get the number of flags:
package main
import "fmt"
import "flag"
func main() {
flag.Bool("a", true, "A value");
flag.Bool("b", true, "B value");
flag.Parse();
fmt.Println(flag.NFlag())
}
Test:
$ go run test.go
0
$ go run test.go -a
1
$ go run test.go -a -b
2