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: trace is broken for strings with new lines #755

Open riacataquian opened 3 years ago

riacataquian commented 3 years ago

Given echo.sh as the file input:

$ cat echo.sh
#!/bin/bash

set -ex

s="The default format for %v is:
bool:                    %t
int, int8 etc.:          %d
uint, uint8 etc.:        %d, %#x if printed with %#v
float32, complex64, etc: %g
string:                  %s
chan:                    %p
pointer:                 %p"
echo "$s"

In bash, the trace for the variable and echo expression is printed as echo would:

$ ./test.sh
+ s='The default format for %v is:\n
bool:                    %t
int, int8 etc.:          %d
uint, uint8 etc.:        %d, %#x if printed with %#v
float32, complex64, etc: %g
string:                  %s
chan:                    %p
pointer:                 %p'
+ echo 'The default format for %v is:\n
bool:                    %t
int, int8 etc.:          %d
uint, uint8 etc.:        %d, %#x if printed with %#v
float32, complex64, etc: %g
string:                  %s
chan:                    %p
pointer:                 %p'
The default format for %v is:\n
bool:                    %t
int, int8 etc.:          %d
uint, uint8 etc.:        %d, %#x if printed with %#v
float32, complex64, etc: %g
string:                  %s
chan:                    %p
pointer:                 %p

Gosh's trace does not print the whitespaces properly:

$ ./gosh test.sh
+ s=$'The default format for %v is:\\n\nbool:                    %t\nint, int8 etc.:          %d\nuint, uint8 etc.:        %d, %#x if printed with %#v\nfloat32, complex64, etc: %g\nstring:                  %s\nchan:                    %p\npointer:                 %p'
+ echo $'The default format for %v is:\\n\nbool:                    %t\nint, int8 etc.:          %d\nuint, uint8 etc.:        %d, %#x if printed with %#v\nfloat32, complex64, etc: %g\nstring:                  %s\nchan:                    %p\npointer:                 %p'
The default format for %v is:\n
bool:                    %t
int, int8 etc.:          %d
uint, uint8 etc.:        %d, %#x if printed with %#v
float32, complex64, etc: %g
string:                  %s
chan:                    %p
pointer:                 %p
mvdan commented 3 years ago

This is probably to do with how syntax.Quote deals with newlines. I'm a bit confused, because the current heuristic only reaches for $' if there are any non-printable or invalid characters in the string.