Mason
Mason

Reputation: 15

Detect if Powershell or CMD with Rust

I'm writing a CLI app in Rust and need to run commands differently depending on if it is being run in CMD or Powershell. There's this SO question that gives a command "(dir 2>&1 *`|echo CMD);&<# rem #>echo POWERSHELL" to run to output "CMD" or "POWERSHELL", but I can't run that as a Command in Rust.

This code returns the following error: Error { kind: NotFound, message: "program not found" }

let output = Command::new("(dir 2>&1 *`|echo CMD);&<# rem #>echo POWERSHELL")
        .output();

The problem is that some CMD/PowerShell commands don't work from Rust's std::process::Command and need to be called directly with CMD or PowerShell, but without that command, I can't seem to figure out how to detect the shell.

Idk if there's another way with Rust to determine what Windows shell is being ran, but any consistent method would also work for what I have in mind.

Update: To clarify my use case, I'm writing a program to set environment variables temporarily and run a given command provided by the user.

# sets $Env:ENV1=VALUE, then runs the command "dir" with args ["env:"]
temporary-env -e ENV1=VALUE1 dir -- env:

This example doesn't needs to determine the shell type, but other commands like dir have different syntax for args and parameters based on which shell is used, so I want to replicate that behavior based on which shell.

Upvotes: 1

Views: 1266

Answers (2)

phuclv
phuclv

Reputation: 41753

Regardless of the platform, whether Windows, Linux, BSD, macOS... you never need to determine the current shell type. You decide the shell you want to use and pass a command in that syntax. If you need to run a PowerShell command just run

powershell "temporary-env -e ENV1=VALUE1 dir -- env:"
powershell "$env:MYVAR = 'value'; somecommand"

powershell -c dir will always be run as a PowerShell command so the syntax and output will always be consistent. Similarly bash -c dir or zsh -c dir also runs a command in that shell

You can't detect the shell environment reliably because programs aren't always run from a terminal, and the parent can strip environment information when executing the child process. The only thing you can do is to walk the process tree to see if any ancestor is a known shell, but of course it won't always work


Update: To clarify my use case, I'm writing a program to set environment variables temporarily and run a given command provided by the user.

You still need to ask the user about the shell they want to use. Even in *nix there are lots of shells like sh, fish, pwsh, nushell, zsh, csh, ash, dash, pysh... All of them have different syntax and the command may likely fail or produce unexpected output if running in the wrong shell.
How do you know that the user is using pysh? What if the user wants to run a zsh command while in fish? The best thing you can do is to assume a default shell if the user doesn't tell you that, like /bin/sh on *nix and cmd on Windows (or powershell if you don't intend to support Windows older than Vista)

Upvotes: 1

stackprotector
stackprotector

Reputation: 13412

You can execute commands that will only work in one shell (but not crash in the other) to determine which shell you are using. E. g.:

echo %PATH%

Will output the content of your PATH environment variable in CMD, but just the string %PATH% in PowerShell. Vice versa:

echo $env:Path

Will output the content of your PATH environment variable in PowerShell, but just the string $env:Path in CMD. So, depending on the output, you can make a guess on which shell you are using.

This may currently work between CMD and PowerShell, but as phuclv already stated, this is not a stable design for a software. What if the user chooses a third - yet unknown - shell?

Upvotes: 2

Related Questions