Skip to content

fix(shellenv): don't escape newlines in exported env var values (#2814)#2925

Open
mikeland73 wants to merge 2 commits into
mainfrom
claude/focused-goldberg-emzfur
Open

fix(shellenv): don't escape newlines in exported env var values (#2814)#2925
mikeland73 wants to merge 2 commits into
mainfrom
claude/focused-goldberg-emzfur

Conversation

@mikeland73

Copy link
Copy Markdown
Collaborator

Summary

Fixes #2814.

eval "$(devbox global shellenv)" could print bash: 1__bp_interactive_mode: ambiguous redirect at every prompt when an environment variable (e.g. a PROMPT_COMMAND set by bash-preexec) contained newlines.

Root cause

exportify (internal/devbox/envvars.go) emits each variable as export KEY="value";, escaping special characters inside the double quotes. It escaped \n by writing a backslash before the newline, producing \<newline>:

case '$', '`', '"', '\\', '\n':
    strb.WriteRune('\\')

Inside double quotes the shell treats a backslash-newline as a line continuation and removes it entirely, collapsing a multi-line value onto one line. A bare newline inside double quotes is already literal, so the escaping was both unnecessary and corrupting.

For the reporter's PROMPT_COMMAND, the lines ... >/dev/null 2>&1 and __bp_interactive_mode were joined into ... 2>&1__bp_interactive_mode, so the 2>&1 redirect target became 1__bp_interactive_mode — hence the "ambiguous redirect" error.

Minimal demonstration of the shell behavior:

$ eval 'export A="line1\
2>&1\
tail"'; printf '[%s]\n' "$A"
[line12>&1tail]          # backslash-newline (old behavior) — corrupted

$ eval 'export B="line1
2>&1
tail"'; printf '[%s]\n' "$B"
[line1
2>&1
tail]                   # bare newline (new behavior) — correct

Fix

Drop \n from the set of characters escaped inside double quotes, so newlines are emitted literally. The exportifyNushell path already emits newlines literally, so this makes the two consistent.

How was it tested?

  • Added TestExportifyPreservesNewlines, which pins the multi-line output and asserts no \<newline> line-continuation is produced.
  • go test ./internal/devbox/ -run 'TestExportify|TestIsValidEnvName' — passes.
  • gofmt -l and go vet ./internal/devbox/ — clean.

/cc @proedie (issue reporter) — thanks for the precise diagnosis and workaround in the report.

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.

🤖 Generated with Claude Code

https://claude.ai/code/session_01WzomNNnDLmX4LMZ4aPtYvm


Generated by Claude Code

exportify escaped newlines inside double-quoted export values as
`\<newline>`. Inside double quotes the shell treats a backslash-newline
as a line continuation and removes it, collapsing a multi-line value
onto a single line. A bare newline inside double quotes is already
literal, so the escaping was both unnecessary and corrupting.

This corrupted, for example, a PROMPT_COMMAND set by bash-preexec whose
`... 2>&1` and `__bp_interactive_mode` lines got joined into
`... 2>&1__bp_interactive_mode`, producing a
"1__bp_interactive_mode: ambiguous redirect" error at every prompt when
running `eval "$(devbox global shellenv)"`.

Drop `\n` from the set of characters escaped inside double quotes and
add a regression test pinning the multi-line output.

Fixes #2814

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WzomNNnDLmX4LMZ4aPtYvm
Copilot AI review requested due to automatic review settings July 17, 2026 14:07

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR fixes a shellenv corruption bug where exportify escaped \n inside double-quoted values as \<newline>, which Bash interprets as a line continuation and strips—collapsing multiline env var values (notably PROMPT_COMMAND) and triggering errors like “ambiguous redirect”.

Changes:

  • Stop escaping newline characters in internal/devbox/envvars.go when emitting export KEY="value";.
  • Add a regression test to ensure multiline values are preserved and no \\\n line-continuation sequence is produced.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated no comments.

File Description
internal/devbox/envvars.go Removes newline from the set of escaped characters in exportify, with clarifying commentary about shell semantics.
internal/devbox/envvars_test.go Adds TestExportifyPreservesNewlines to lock in correct multiline export behavior and prevent regressions.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Rename the loop variable `r` to `char` and hoist the explanatory
comment out of the loop body so the variable's declaration-to-use
distance stays within golangci-lint's varnamelen max-distance.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WzomNNnDLmX4LMZ4aPtYvm
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

Bash: ambiguous redirect on eval "$(devbox global shellenv)"

3 participants