Skip to content

Commit ccb0bbd

Browse files
committed
fix(interpreter): expand command substitutions in assoc array keys
Associative array assignments where the key is a command substitution (e.g. m["$(echo hello)"]="world") silently produced an empty key. Add async expand_assoc_key() that parses the subscript as a full Word and expands it with expand_word() when it contains $( or backtick. Closes #872
1 parent 9752fe0 commit ccb0bbd

File tree

2 files changed

+26
-1
lines changed

2 files changed

+26
-1
lines changed

crates/bashkit/src/interpreter/mod.rs

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3129,7 +3129,7 @@ impl Interpreter {
31293129
if let Some(index_str) = &assignment.index {
31303130
let resolved_name = self.resolve_nameref(&assignment.name).to_string();
31313131
if self.assoc_arrays.contains_key(&resolved_name) {
3132-
let key = self.expand_variable_or_literal(index_str);
3132+
let key = self.expand_assoc_key(index_str).await?;
31333133
let is_new_entry = self
31343134
.assoc_arrays
31353135
.get(&resolved_name)
@@ -7791,6 +7791,21 @@ impl Interpreter {
77917791
s.to_string()
77927792
}
77937793

7794+
/// Fully expand an associative array key, including command substitutions.
7795+
/// Falls back to `expand_variable_or_literal` for keys without `$(` or backtick.
7796+
async fn expand_assoc_key(&mut self, s: &str) -> Result<String> {
7797+
if s.contains("$(") || s.contains('`') {
7798+
let word = Parser::parse_word_string_with_limits(
7799+
s,
7800+
self.limits.max_ast_depth,
7801+
self.limits.max_parser_operations,
7802+
);
7803+
self.expand_word(&word).await
7804+
} else {
7805+
Ok(self.expand_variable_or_literal(s))
7806+
}
7807+
}
7808+
77947809
/// THREAT[TM-INJ-009]: Check if a variable name is an internal marker.
77957810
fn is_internal_variable(name: &str) -> bool {
77967811
is_internal_variable(name)

crates/bashkit/tests/spec_cases/bash/assoc-arrays.test.sh

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -173,6 +173,16 @@ b=2
173173
c=3
174174
### end
175175

176+
### assoc_key_command_substitution
177+
declare -A m=()
178+
m["$(echo hello)"]="world"
179+
echo "count: ${#m[@]}"
180+
for k in "${!m[@]}"; do echo "key=[$k] val=[${m[$k]}]"; done
181+
### expect
182+
count: 1
183+
key=[hello] val=[world]
184+
### end
185+
176186
### assoc_iteration
177187
declare -A m
178188
m[a]="1"

0 commit comments

Comments
 (0)