我正在尝试获取正在执行命令行程序的当前交互式 shell 的名称。在我的终端中,我可以运行以下命令:
λ ps -p $$ -o 'comm='
zsh
并且它正确地打印了 shell 的名称。如果我用
sh -c
运行它,会得到相同的结果:
λ sh -c "ps -p $$ -o 'comm='"
zsh
用 Bash 尝试,结果相同:
λ bash
amir@shabani:~/Code/ami$ ps -p $$ -o 'comm='
bash
amir@shabani:~/Code/ami$ sh -c "ps -p $$ -o 'comm='"
bash
现在,当我在 Rust 程序中执行相同的命令时,它会打印
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
}
}
无论我在哪里运行程序,
zsh
或bash
,它总是打印sh
。有什么问题吗?
获得 something 的最简单方法是获取父进程(生成进程)的名称。这不一定是生成您的 shell:如果您通过
cargo run
运行程序,例如它将是 Cargo。但如果你直接从 shell 运行程序,它就会是你想要的。
sysinfo
crate 以跨平台的方式获取父进程:
fn main() {
let system = sysinfo::System::new_with_specifics(
sysinfo::RefreshKind::new().with_processes(sysinfo::ProcessRefreshKind::new()),
);
let my_pid = sysinfo::get_current_pid().expect("unable to get PID of the current process");
let parent_pid = system
.process(my_pid)
.expect("no self process?")
.parent()
.expect("unable to get parent process");
let parent_process = system
.process(parent_pid)
.expect("unable to get parent process");
let parent_name = parent_process.name();
println!("Spawning shell (or not): {parent_name}");
}
如果你想要更精确的分析,你可以从枚举所有活着的 shell 进程开始,并递归地询问它们的子进程。如果您的进程在列表中,则意味着它是从此 shell 生成的(直接或间接)。 请注意,这仅在 shell 还活着的情况下才有效;如果退出就无法工作。