Escape backtick in Go (string used in exec.Command) - go

Given this code, I can't figure out how to escape the backtick.
var (
MY_STRING = "something`something"
)
cmd := fmt.Sprintf("MY_ENV=%q;", MY_STRING)
out, err := exec.Command("bash", "-c", cmd).CombinedOutput()
// results in MY_ENV="something`something" ie unfinished input
I've tried the below but it results in "unknown escape sequence". It does work in the shell obviously. I've also tried to combine strings and raw string literals but with no success. How can I escape the backtick please?
var (
MY_STRING = "something\`something"
)

Use ' to escape ` in Bourne shells. And no need to quote the string.
MY_STRING := "something'`'something"
cmd := fmt.Sprintf("MY_ENV=%s;", MY_STRING)
out, err := exec.Command("bash", "-c", cmd).CombinedOutput()

The backtick doesn’t need escaping for Go to leave it in the string (ref).
However, bash will treat backticks outside of a string as subshell syntax. The easiest way to escape a backtick in bash is to include it in a single-quoted string:
var MY_STRING = "'something`something'"
But since you’re using %q in your format string, this won’t behave as expected.
Instead, you can use the solution posted on this question. Bash requires double escaping the backtick (\\\`) inside double quotes. There’s a full explanation for why this is necessary in that linked question. Since Go also uses \ as an escape character, you’ll need to double up each one:
var MY_STRING = "something\\\\\\`something"

you can try //go:embed foo.sh embed external shell file to your code. like this:
//go:embed yourshell.sh
var yourshell string
put the shell file in the same folder of your code.
details of go embed : https://pkg.go.dev/embed

Related

How to Print ascii text in go like python does

how to print ascii-text in go language like python does
like picture shown below
Using python
Using Golang
The problem is that your text contains backtick (`), which happen to be delimiter character for golang's raw string literal. This situation is comparable to your python code had your text contains 3 consecutive double-quotes, which is the delimiter being used in your python code.
I don't see any quick escape from this situation without modifying your ascii text, as we don't have other options for raw string delimiter in golang like we have in python. You may want to store your ascii text in a text file and read it from there :
import (
....
....
"io/ioutil"
)
func banner() string {
b, err := ioutil.ReadFile("ascii.txt")
if err != nil {
panic(err)
}
fmt.Println(string(b))
}
If you're ok with slight modification to the ascii text source, then you can temporarily use other character that isn't used anywhere else in the ascii text to represent backtick, and then do string replacement to put the actual backtick in place. Or, you can use fmt.Sprintf to supply the problematic backtick :
ascii := fmt.Sprintf(`....%c88b...`, '`')
fmt.Println(ascii)
// output:
// ....`88b...
Yes but you have to split lines with backtick and put them quoted into standard double quote ”.
... +
“888 6(, ` ‘ “ +
...

Unable to use backslash `\` in Golang os.Arg variable

I have made a program in Golang and I am trying to use a file as the first argument when launching my program.
For example: ./goprogram.exe C:\Acidic\image.png
When my program tries to use the os.Arg[1] variable which should be the link to the image.png file, it returns the string without any of the backslashes (C:Acidicimage.png).
How can I use the whole string of an argument without characters being escaped?
I have made a little example:
package main
import (
"fmt"
"os"
)
func main() {
if len(os.Args) >= 2 {
fmt.Println(os.Args[1])
}
}
I run go run args.go C:\Users\image.png and it outputs C:Usersimage.png
Put any argument between quotes:
./goprogram.exe "C:\Acidic\image.png"
The issue appears to be your shell. Try quoting the file path:
./goprogram.exe 'C:\Acidic\image.png' # prevents escape sequence execution
A string fo type C:\Acidic\image.png (with single \'s) is not a valid string in Go (invalid escape sequence \A, etc) and would not even compile.

Normalizing text input to ASCII

I am building a small tool which parses a user's input and finds common pitfalls in writing and flags them so the user can improve their text. So far everything works well except for text that has curly quotes compared to normal ASCII straight quotes. I have a hack now which will do a string replacement for opening (and closing) single curly quotes and double opening (and close) curly quotes like so:
cleanedData := bytes.Replace([]byte(data), []byte("’"), []byte("'"), -1)
I feel like there must be a better way to handle this in the stdlib so I can also convert other non-ascii characters to an ascii equivalent. Any help would be greatly appreciated.
The strings.Map function looks to me like what you want.
I don't know of a generic 'ToAscii' type function, but Map has a nice approach for mapping runes to other runes.
Example (updated):
func main() {
data := "Hello “Frank” or ‹François› as you like to be ‘called’"
fmt.Printf("Original: %s\n", data)
cleanedData := strings.Map(normalize, data)
fmt.Printf("Cleaned: %s\n", cleanedData)
}
func normalize(in rune) rune {
switch in {
case '“', '‹', '”', '›':
return '"'
case '‘', '’':
return '\''
}
return in
}
Output:
Original: Hello “Frank” or ‹François› as you like to be ‘called’
Cleaned: Hello "Frank" or "François" as you like to be 'called'

Go regexp: match three asterisks

So I did this:
r, _ := regexp.Compile("* * *")
r2 := r.ReplaceAll(b, []byte("<hr>"))
and got:
panic: runtime error: invalid memory address or nil pointer dereference
So I figured I had to escape them:
r, _ := regexp.Compile("\* \* \*")
But got unknown escape secuence
I'm a Go Beginner. What am I doing wrong?
You are not checking errors.
regexp.Compile gives you two results:
the compiled pattern (or nil)
the error while compiling the pattern (or nil)
You are ignoring the error and accessing the nil result. Observe (on play):
r, err := regexp.Compile("* * *")
fmt.Println("r:", r)
fmt.Println("err:", err)
Running this code will show you that, indeed there is an error. The error is:
error parsing regexp: missing argument to repetition operator: *
So yes, you are right, you have to escape the repetition operator *. You tried the following:
r, err := regexp.Compile("\* \* \*")
And consequently you got the following error from the compiler:
unknown escape sequence: *
Since there are a number of escape sequences like \n or \r for special characters that you do not have on your keyboard but want to have in strings, the compiler tries to insert these characters. \* is not a valid escape sequence and thus the compiler fails to do the replacement. What you want to do is to escape the escape sequence so that the regexp parser can do its thing.
So, the correct code is:
r, err := regexp.Compile("\\* \\* \\*")
The simplest way of dealing with these kind of quirks is using the raw string literals ("``") instead of normal quotes:
r, err := regexp.Compile(`\* \* \*`)
These raw strings ignore escape sequences altogether.
Adding to #VonC's answer, regexp aren't always the answer and are generally slower than using strings.*.
For a complex expression, sure regexp is awesome, however if you just want to match a string and replace it then, strings.Replacer is the way to go:
var asterisksReplacer = strings.NewReplacer(`* * *`, `<hr>`)
func main() {
fmt.Println(asterisksReplacer.Replace(`xxx * * * yyy *-*-* zzz* * *`))
}
playground
Try escaping your '*' (since '*' is a special character used for repetition in the re2 syntax)
r, err := regexp.Compile(`\* \* \*`)
// and yes, always check the error
// or at least use regexp.MustCompile() if you want to fail fast
Note the use of back quotes `` for the string literal.

How to strings.Split on newline?

I'm trying to do the rather simple task of splitting a string by newlines.
This does not work:
temp := strings.Split(result,`\n`)
I also tried ' instead of ` but no luck.
Any ideas?
You have to use "\n".
Splitting on `\n`, searches for an actual \ followed by n in the text, not the newline byte.
playground
For those of us that at times use Windows platform, it can
help remember to use replace before split:
strings.Split(strings.ReplaceAll(windows, "\r\n", "\n"), "\n")
Go Playground
It does not work because you're using backticks:
Raw string literals are character sequences between back quotes ``. Within the quotes, any character is legal except back quote. The value of a raw string literal is the string composed of the uninterpreted (implicitly UTF-8-encoded) characters between the quotes; in particular, backslashes have no special meaning and the string may contain newlines.
Reference: http://golang.org/ref/spec#String_literals
So, when you're doing
strings.Split(result,`\n`)
you're actually splitting using the two consecutive characters "\" and "n", and not the character of line return "\n". To do what you want, simply use "\n" instead of backticks.
Your code doesn't work because you're using backticks instead of double quotes. However, you should be using a bufio.Scanner if you want to support Windows.
import (
"bufio"
"strings"
)
func SplitLines(s string) []string {
var lines []string
sc := bufio.NewScanner(strings.NewReader(s))
for sc.Scan() {
lines = append(lines, sc.Text())
}
return lines
}
Alternatively, you can use strings.FieldsFunc (this approach skips blank lines)
strings.FieldsFunc(s, func(c rune) bool { return c == '\n' || c == '\r' })
import regexp
var lines []string = regexp.MustCompile("\r?\n").Split(inputString, -1)
MustCompile() creates a regular expression that allows to split by both \r\n and \n
Split() performs the split, seconds argument sets maximum number of parts, -1 for unlimited
' doesn't work because it is not a string type, but instead a rune.
temp := strings.Split(result,'\n')
go compiler: cannot use '\u000a' (type rune) as type string in argument to strings.Split
definition: Split(s, sep string) []string

Resources