fix(shellenv): preserve newlines in exported env values (#2814)#2919
Open
mikeland73 wants to merge 2 commits into
Open
fix(shellenv): preserve newlines in exported env values (#2814)#2919mikeland73 wants to merge 2 commits into
mikeland73 wants to merge 2 commits into
Conversation
exportify escaped a newline inside a double-quoted value as a backslash-newline. In POSIX shells a backslash-newline is a line continuation that is removed on eval, so any multiline env value had its newlines silently deleted, joining adjacent lines. For a multiline PROMPT_COMMAND this turned `... 2>&1\<newline>foo` into `... 2>&1foo`, making the shell emit "ambiguous redirect" on every prompt. A literal newline inside double quotes is preserved as-is and needs no escaping, so stop escaping it. Fixes #2814 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016JemcBvhaZqahAzACV4aQF
Contributor
There was a problem hiding this comment.
Pull request overview
This pull request fixes incorrect POSIX-shell export generation for environment variables whose values contain literal newlines (e.g., multiline PROMPT_COMMAND). It adjusts exportify so newlines are emitted literally inside double quotes (instead of being turned into backslash-newline line continuations that eval removes), and adds a regression test to lock in the behavior.
Changes:
- Stop escaping
\nininternal/devbox/envvars.goPOSIX-shell export generation to preserve multiline values. - Add
TestExportifyMultilineValueto ensure multiline values round-trip without producing\\\nline continuations.
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated no comments.
| File | Description |
|---|---|
| internal/devbox/envvars.go | Updates exportify escaping rules to preserve literal newlines inside double-quoted export values (fix for #2814). |
| internal/devbox/envvars_test.go | Adds a regression test validating multiline values remain multiline and never contain backslash-newline. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
The explanatory comment inside the rune loop widened the scope of the single-letter loop variable `r`, tripping golangci-lint's varnamelen. Move the comment above the loop so the loop body matches the original structure; no behavior change. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016JemcBvhaZqahAzACV4aQF
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Fixes #2814.
eval "$(devbox global shellenv)"printedbash: 1__bp_interactive_mode: ambiguous redirectat every prompt when the environment contained a multiline value (in the reporter's case aPROMPT_COMMANDbuilt by bash-preexec / an elementary-terminal dbus hook).Root cause
exportify(internal/devbox/envvars.go) emits each value asexport KEY="…";and escapes special characters by prefixing them with\. It also escaped\n, so a newline in a value was written as a backslash + literal newline:Inside double quotes, a backslash-newline is a line continuation — the shell removes it entirely on
eval. So the newline was silently deleted and the two lines were joined:2>&1__bp_interactive_modemakes the redirect target1__bp_interactive_mode, which bash rejects as an ambiguous redirect — exactly the reported error.Fix
A literal newline inside double quotes is preserved as-is and needs no escaping (per the POSIX quoting rules, only
$,`,", and\are special there). Soexportifynow stops escaping\nand emits the newline literally, keeping multiline values intact. A regression test pins the behavior.The change is limited to the POSIX-shell export path;
exportifyNushellalready did not escape newlines and is untouched.How was it tested?
go test ./internal/devbox/ -run TestExportify— passes, including the newTestExportifyMultilineValue.go vet ./internal/devbox/andgofmt -l— clean.End-to-end in real bash, reproducing the reporter's value. Before the fix the sourced value collapses to
… 2>&1__bp_interactive_mode(deleted newlines → ambiguous redirect); after the fix the newlines are preserved:Community Contribution License
All community contributions in this pull request are licensed to the project
maintainers under the terms of the
Apache 2 License.
By creating this pull request, I represent that I have the right to license the
contributions to the project maintainers under the Apache 2 License as stated in
the
Community Contribution License.
cc @proedie (issue reporter) — thanks for the precise diagnosis, including the exact line that needed moving.
🤖 Generated with Claude Code
https://claude.ai/code/session_016JemcBvhaZqahAzACV4aQF
Generated by Claude Code