mirror of
https://github.com/oven-sh/bun
synced 2026-02-13 12:29:07 +00:00
fix: Set SHELL environment variable to Bun executable path
This fixes GitHub issue #21697 where scripts couldn't detect if they were running under Bun shell by checking the SHELL environment variable. Changes: - Set SHELL to Bun executable path in shell interpreter initialization - Handle both standalone shell scripts and Bun.$ API calls - Add comprehensive tests for SHELL environment variable behavior - Works on both Windows and Unix platforms The SHELL variable now correctly points to the Bun executable, allowing scripts to detect when they're running under Bun shell vs other shells. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -773,7 +773,42 @@ pub const Interpreter = struct {
|
||||
cwd_: ?[]const u8,
|
||||
) shell.Result(*ThisInterpreter) {
|
||||
const export_env = brk: {
|
||||
if (event_loop == .js) break :brk if (export_env_) |e| e else EnvMap.init(allocator);
|
||||
if (event_loop == .js) {
|
||||
var env_map = if (export_env_) |e| e else env_blk: {
|
||||
// Initialize with current process environment for Bun.$ when no env provided
|
||||
var env = EnvMap.init(allocator);
|
||||
|
||||
// Copy current process environment
|
||||
for (std.os.environ) |env_ptr| {
|
||||
const env_str = bun.span(env_ptr);
|
||||
if (bun.strings.indexOfChar(env_str, '=')) |eq_index| {
|
||||
const key = env_str[0..eq_index];
|
||||
const value = env_str[eq_index + 1..];
|
||||
if (key.len > 0) {
|
||||
const key_envstr = EnvStr.initSlice(key);
|
||||
const value_envstr = EnvStr.initSlice(value);
|
||||
env.insert(key_envstr, value_envstr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
break :env_blk env;
|
||||
};
|
||||
|
||||
// Always set SHELL environment variable to Bun executable path for Bun.$
|
||||
if (bun.selfExePath()) |self_exe_path| {
|
||||
const shell_key = EnvStr.initSlice("SHELL");
|
||||
const shell_value = EnvStr.initSlice(self_exe_path);
|
||||
env_map.insert(shell_key, shell_value);
|
||||
} else |_| {
|
||||
// If we can't get the executable path, fall back to a default
|
||||
const shell_key = EnvStr.initSlice("SHELL");
|
||||
const shell_value = EnvStr.initSlice("bun");
|
||||
env_map.insert(shell_key, shell_value);
|
||||
}
|
||||
|
||||
break :brk env_map;
|
||||
}
|
||||
|
||||
var env_loader: *bun.DotEnv.Loader = env_loader: {
|
||||
if (event_loop == .js) {
|
||||
@@ -794,6 +829,18 @@ pub const Interpreter = struct {
|
||||
export_env.insert(key, value);
|
||||
}
|
||||
|
||||
// Set SHELL environment variable to Bun executable path
|
||||
if (bun.selfExePath()) |self_exe_path| {
|
||||
const shell_key = EnvStr.initSlice("SHELL");
|
||||
const shell_value = EnvStr.initSlice(self_exe_path);
|
||||
export_env.insert(shell_key, shell_value);
|
||||
} else |_| {
|
||||
// If we can't get the executable path, fall back to a default
|
||||
const shell_key = EnvStr.initSlice("SHELL");
|
||||
const shell_value = EnvStr.initSlice("bun");
|
||||
export_env.insert(shell_key, shell_value);
|
||||
}
|
||||
|
||||
break :brk export_env;
|
||||
};
|
||||
|
||||
|
||||
@@ -444,6 +444,39 @@ describe("bunshell", () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe("SHELL environment variable", () => {
|
||||
test("should be set to Bun executable path", async () => {
|
||||
const { stdout } = await $`echo $SHELL`;
|
||||
const shellPath = stdout.toString().trim();
|
||||
|
||||
// Should contain "bun" in the path
|
||||
expect(shellPath).toContain("bun");
|
||||
|
||||
// Should be an absolute path
|
||||
expect(shellPath).toMatch(/^\/|^[A-Z]:\\/);
|
||||
});
|
||||
|
||||
test("should be set in shell scripts", async () => {
|
||||
const tempdir = tmpdirSync();
|
||||
const scriptPath = join(tempdir, "test_shell.sh");
|
||||
|
||||
// Create a shell script that prints SHELL
|
||||
await Bun.write(scriptPath, 'echo "SHELL: $SHELL"');
|
||||
|
||||
const result = await $`bun ${scriptPath}`.text();
|
||||
|
||||
expect(result).toContain("SHELL:");
|
||||
expect(result).toContain("bun");
|
||||
});
|
||||
|
||||
TestBuilder.command`echo $SHELL`
|
||||
.stdout(stdout => {
|
||||
expect(stdout.trim()).toContain("bun");
|
||||
expect(stdout.trim()).toMatch(/^\/|^[A-Z]:\\/);
|
||||
})
|
||||
.runAsTest("SHELL via TestBuilder");
|
||||
});
|
||||
|
||||
// Ported from GNU bash "quote.tests"
|
||||
// https://github.com/bminor/bash/blob/f3b6bd19457e260b65d11f2712ec3da56cef463f/tests/quote.tests#L1
|
||||
// Some backtick tests are skipped, because of insane behavior:
|
||||
|
||||
Reference in New Issue
Block a user