Skip to content

Commit 330fee5

Browse files
Bash c stdin was available to all commands vs. just the first one (#105)
* WIP: save current work * removing the debug tests used to hone in on the issue * remove more tests and test data * linter ! --------- Co-authored-by: Robert Yates <Robert_Yates@us.ibm.com>
1 parent ac739c0 commit 330fee5

2 files changed

Lines changed: 20 additions & 0 deletions

File tree

src/commands/bash/bash.test.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -237,5 +237,16 @@ cat /tmp/test.txt`,
237237
expect(result.stdout).toBe("line2\n");
238238
expect(result.exitCode).toBe(0);
239239
});
240+
241+
it("should handle command substitution with grep and head in piped bash -c", async () => {
242+
const env = new Bash();
243+
// This test demonstrates a bug where grep with no matches followed by head
244+
// incorrectly passes through the original stdin instead of empty output
245+
const result = await env.exec(
246+
'echo "test" | bash -c \'RESULT=$(cat | grep "nomatch" | head -1); echo "RESULT=[$RESULT]"\'',
247+
);
248+
expect(result.stdout).toBe("RESULT=[]\n");
249+
expect(result.exitCode).toBe(0);
250+
});
240251
});
241252
});

src/interpreter/pipeline-execution.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,12 +43,21 @@ export async function executePipeline(
4343
for (let i = 0; i < node.commands.length; i++) {
4444
const command = node.commands[i];
4545
const isLast = i === node.commands.length - 1;
46+
const isFirst = i === 0;
4647

4748
// In a multi-command pipeline, each command runs in a subshell context
4849
// where $_ starts empty (subshells don't inherit $_ from parent in same way)
4950
if (isMultiCommandPipeline) {
5051
// Clear $_ for each pipeline command - they each get fresh subshell context
5152
ctx.state.lastArg = "";
53+
54+
// After the first command, clear groupStdin so subsequent commands
55+
// only see stdin from the pipeline (even if empty), not the original groupStdin
56+
// This prevents commands like head from incorrectly falling back to groupStdin
57+
// when they receive empty output from a previous command (e.g., grep with no matches)
58+
if (!isFirst) {
59+
ctx.state.groupStdin = undefined;
60+
}
5261
}
5362

5463
// Determine if this command runs in a subshell context

0 commit comments

Comments
 (0)