Skip to content

bug: single-quoted strings inside $(...) lose embedded double quotes #803

@chaliy

Description

@chaliy

Problem

When a single-quoted string containing double quotes is used inside a command substitution $(...), the double quotes are stripped from the output. This breaks all JSON handling in pipe chains inside $(...).

Direct execution works correctly. The bug is in how the parser/expander handles single-quoted content within command substitution.

Reproduction

# Direct — correct:
echo '{"a":1}'
# Output: {"a":1}

# In command substitution — WRONG:
x="$(echo '{"a":1}')"
echo "${x}"
# Expected: {"a":1}
# Actual:   {a:1}

Impact

This is critical for any framework that processes JSON in bash. wedow/harness uses this pattern pervasively:

# Harness hook pipeline — every hook does this:
payload="$(cat)"
tools="$(echo "${tools}" | jq --argjson s '{"name":"bash"}' '. + [$s]')"
#                                          ^^^^^^^^^^^^^^^^^
#                                          quotes stripped → jq gets invalid input → empty output

Workaround: assign the JSON to a variable first, then use the variable:

# This works:
json_str='{"a":1}'
x="$(echo "${json_str}")"
echo "${x}"
# Output: {"a":1}

Test cases

# Basic: single quotes with embedded double quotes in $()
x="$(echo '{"key":"value"}')"
echo "${x}"
# Expected: {"key":"value"}

# Pipe chain in $()
result="$(echo '{"a":1}' | jq '.')"
echo "${result}"
# Expected: {
#   "a": 1
# }

# Multiple levels of quoting
y="$(echo 'say "hello" please')"
echo "${y}"
# Expected: say "hello" please

# Nested command substitution
z="$(echo "inner: $(echo '{"b":2}')")"
echo "${z}"
# Expected: inner: {"b":2}

# Backtick form (should match)
w="$(echo '"quoted"')"
echo "${w}"
# Expected: "quoted"

# Single quotes without double quotes — should be fine
v="$(echo 'no quotes here')"
echo "${v}"
# Expected: no quotes here

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions