mvdan / sh

A shell parser, formatter, and interpreter with bash support; includes shfmt
https://pkg.go.dev/mvdan.cc/sh/v3
BSD 3-Clause "New" or "Revised" License
7.29k stars 345 forks source link

interp: bash escape character's literal value are printed #748

Closed riacataquian closed 3 years ago

riacataquian commented 3 years ago

interp via gosh produces the result:

$ go run ./cmd/gosh -c "echo "hello\nnewline"; echo 'hello\\nnewline'"
hellonnewline
hello\nnewline

But basing from https://www.gnu.org/software/bash/manual/html_node/Escape-Character.html#:~:text=A%20non%2Dquoted%20backslash%20'%20%5C,with%20the%20exception%20of%20newline%20:

3.1.2.1 Escape Character A non-quoted backslash ‘\’ is the Bash escape character. It preserves the literal value of the next character that follows, with the exception of newline. If a \newline pair appears, and the backslash itself is not quoted, the \newline is treated as a line continuation (that is, it is removed from the input stream and effectively ignored).

The expectation is \n is to be treated as a new line and \\n as a literal value:

$ echo "hello\nnewline"; echo 'hello\\nnewline'
hello
newline
hello\nnewline
mvdan commented 3 years ago

Hm. I think you're getting slightly confused, because when you use gosh -c "...", that's already double-quoting the input program, so your "inner" double quotes actually get out of the quoting, and back inside.

If you apply the same double quoting to bash, it gets the same result:

$ gosh -c "echo "hello\nnewline"; echo 'hello\\nnewline'"
hellonnewline
hello\nnewline
$ bash -c "echo "hello\nnewline"; echo 'hello\\nnewline'"
hellonnewline
hello\nnewline

A saner approach to test the shells is to start them, paste some input, and then exit:

$ bash
$ echo "hello\nnewline"; echo 'hello\\nnewline'
hello\nnewline
hello\\nnewline
$ exit
exit
$ gosh
$ echo "hello\nnewline"; echo 'hello\\nnewline'
hello\nnewline
hello\\nnewline
$ exit
mvdan commented 3 years ago

I should clarify - -c is entirely fine if your inputs are simple. But if you want to include multiple forms of quoting, then nested quoting gets confusing. Best to start a shell and type in its stdin, or perhaps even a heredoc, like:

$ gosh <<EOF
> echo "foo" 'bar'
> EOF
foo bar
riacataquian commented 3 years ago

Oh right, I missed the quoting. Thanks for the tips! I'll close this ticket then. :)