You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
syntax: printer drops a trailing backslash at EOF, making shfmt non-idempotent #1354
The parser keeps the trailing backslash as a literal: echo foo\ parses to a Lit with value foo\, and the interpreter expands it to foo\ (matching dash/POSIX). But the printer writes that literal verbatim right before the newline it always adds at the end of a file, so the emitted echo foo\<newline> re-parses as a line continuation and the backslash is gone. So the very first format already changes meaning (the literal backslash is dropped), and formatting isn't a fixed point.
It only shows up with an odd number of trailing backslashes at the very end of the input — echo foo\\ and quoted heredoc bodies are fine, since only \<EOF> ends up as a lone literal backslash.
FuzzParsePrint doesn't catch it because it discards the printed output and only checks that Print doesn't error; the printTest helper sidesteps it too, since its idempotency check re-parses the want string without the trailing newline (the comment there already notes that the added newline "can change the meaning of trailing backslashes").
A few directions, and I'm not sure which you'd prefer:
Have the printer emit foo\\ instead of foo\ — same value, survives the newline, idempotent. Downside: it rewrites the literal (foo\ in, foo\\ out).
Drop the final newline when the output would otherwise end in a lone backslash. Downside: that one file wouldn't end in a newline.
Discard the trailing \<EOF> in the parser in Bash mode (Bash drops it, dash keeps it), so echo foo\ formats to echo foo in a single pass. Changes parsing/interp and is variant-specific.
I have (1) working locally with a test, but I'm happy to send whichever approach you'd rather take.
Activity
syntax: add test cases for issue #1354
syntax: escape a lone trailing backslash at the end of a file