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
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
Impact
This is critical for any framework that processes JSON in bash. wedow/harness uses this pattern pervasively:
Workaround: assign the JSON to a variable first, then use the variable:
Test cases