Skip to content

fix(shellenv): preserve newlines in exported env var values (#2814)#2927

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

fix(shellenv): preserve newlines in exported env var values (#2814)#2927
mikeland73 wants to merge 2 commits into
mainfrom
claude/focused-goldberg-5lnwqg

Conversation

@mikeland73

Copy link
Copy Markdown
Collaborator

Summary

Fixes #2814.

eval "$(devbox global shellenv)" produced bash: 1__bp_interactive_mode: ambiguous redirect on every prompt for users whose PROMPT_COMMAND is set up by bash-preexec (newline-separated commands).

Root cause is in exportify (internal/devbox/envvars.go). It escaped every newline inside a double-quoted value as a backslash-newline:

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

In the shell, a backslash-newline inside double quotes is a line continuation — the shell deletes it. So any env var whose value spans multiple lines had its newlines silently stripped and its lines glued together when re-imported. For the reporter's PROMPT_COMMAND, ... 2>&1 was joined onto the following __bp_interactive_mode, yielding ... 2>&1__bp_interactive_mode, which bash parses as a redirect to fd 1__bp_interactive_mode → "ambiguous redirect".

A bare newline inside double quotes is already preserved literally, so the fix is simply to stop escaping it (drop '\n' from the escape set). The nushell exporter already writes newlines literally, so this makes the two consistent.

How was it tested?

  • Added TestExportifyPreservesNewlines, a regression test that asserts a multi-line value round-trips with literal newlines and contains no backslash-newline continuation. It fails on the old code and passes with the fix.
  • go test ./internal/devbox/ -run 'TestExportify|TestIsValidEnvName' — all pass.
  • Confirmed the exact symptom in a shell. Before (escaped):
    $ eval 'export PC="cmd >/dev/null 2>&1\
    __bp_interactive_mode";'
    # PC == "cmd >/dev/null 2>&1__bp_interactive_mode"  -> ambiguous redirect
    
    After (literal newline): the value keeps its newline and the two commands stay separate.

cc @proedie (issue reporter) — thanks for the precise diagnosis and workaround in the report, which pinpointed the exact line.

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_01QGpiSzrugFvBQtAXxkVT75


Generated by Claude Code

exportify escaped newlines inside double-quoted values as
backslash-newline. In the shell, a backslash-newline is a line
continuation that gets deleted, so any env var whose value spans
multiple lines had its newlines silently stripped and its lines glued
together when re-imported via `eval "$(devbox global shellenv)"`.

This corrupted a bash-preexec-style PROMPT_COMMAND, gluing
`... 2>&1` onto the following `__bp_interactive_mode` command and
producing `bash: 1__bp_interactive_mode: ambiguous redirect` on every
prompt.

A bare newline inside double quotes is already preserved literally, so
the fix is simply to stop escaping it. Adds a regression test.

Fixes #2814

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QGpiSzrugFvBQtAXxkVT75
Copilot AI review requested due to automatic review settings July 20, 2026 14:08
The added explanatory comment lengthened the loop body enough that
golangci-lint's varnamelen flagged the single-letter 'r'. Rename it to
'char'.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QGpiSzrugFvBQtAXxkVT75

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 devbox global shellenv exports for multi-line environment variable values (notably PROMPT_COMMAND as configured by bash-preexec), ensuring newlines are preserved instead of being deleted by shell line-continuation semantics.

Changes:

  • Stop escaping \n inside double-quoted export values in exportify, preserving literal newlines.
  • Add a regression test to ensure multi-line values round-trip with literal newlines and do not include backslash-newline 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 Removes newline from the escape set so multi-line env var values remain intact when exported/imported via shell.
internal/devbox/envvars_test.go Adds a regression test covering multi-line export behavior and guarding against reintroducing backslash-newline continuations.

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

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