I'm trying the get the name of the current interactive shell that my command-line program is being executed on. In my terminal, I can run this command:
λ ps -p $$ -o 'comm='
zsh
And it correctly prints the name of the shell. If I run it with sh -c, same results:
λ sh -c "ps -p $$ -o 'comm='"
zsh
Trying it with Bash, same results:
λ bash
amir@shabani:~/Code/ami$ ps -p $$ -o 'comm='
bash
amir@shabani:~/Code/ami$ sh -c "ps -p $$ -o 'comm='"
bash
Now when I execute the same command in a Rust program, it prints sh.
use std::process::{Command, ExitCode};
pub fn shell() -> ExitCode {
let output = Command::new("sh")
.arg("-c")
.arg("ps -p $$ -o 'comm='")
.output()
.expect("Failed to execute command");
if output.status.success() {
let shell_name = String::from_utf8_lossy(&output.stdout);
println!("The current shell is: {}", shell_name.trim());
ExitCode::SUCCESS
} else {
eprintln!("Error executing command");
ExitCode::FAILURE
}
}
No matter where I run the program, zsh or bash, it always prints sh. What's the problem?
The easiest way to have something is to get the name of the parent process (the spawning process). This won't necessarily be the shell that spawned you: if you run the program via
cargo run, for example, it will be Cargo. But if you run the program directly from the shell, it will be what you want.You can use the
sysinfocrate to get the parent process in a cross-platform manner:If you want more precise analysis, you can start from enumerating all living shell processes, and asking for their children recursively. If your process is in the list, that means it was spawned (directly or indirectly) from this shell.
Note that this only work if the shell is still alive; it won't work if it exited.