-
-
Notifications
You must be signed in to change notification settings - Fork 1.6k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Process.run(command, shell: true)
inconsistent on Windows and POSIX
#12873
Comments
Maybe not directly relevant, but there's also this related discussion about |
|
I don't think that's exactly incorrect. Yes, a command could also be a shell built-in or alias. But when invoking that command fails with error 127 it means there is neither a built-in, alias nor file by that name. So file not found would be acceptable IMO. |
Other possible valid one word "commands" I found:
|
What's the significance of "one word commands? Does that have any special meaning? It shouldn't matter what the command is (it can even be a complex shell expression). If a command is not found, the shell returns exit code 127. That implicitly means no file was found that would match the command name. |
Another difference is that on POSIX the shell besides returning exit code 127 also prints a message to stderr (something like |
I mean, there isn't necessary a file involved in the process for shell expressions. |
Well, yes when running a command that is actually a shell built-in, no file will be looked up and it doesn't matter if it exists or not. But then it's not in the error track because the command exists. |
Faire enough. Another alternative is to still return a The advantage being not a breaking change. |
I think I may have confused myself with the behavior of |
Yeah that would align with #12284 But I think communicating this as When the command to be executed is not found, the shell doesn't even attempt to run any process because there is nothing to run. So this should be expressed as an error state of |
Due to the implementation of So a command not found error can be observed in different places: On windows it's directly raised in
|
There's an additional complication with mapping exit codes 127 and 126 to |
"aliases" and "built in shell commands" are not unix-clones only thing. |
For reference I have an experimental branch for dabbling with this: https://github.com/straight-shoota/crystal/pull/new/fix/process-run-raise-file_not_found |
I find it odd that POSIX calls `exit 123` # raises on Windows
$?.exit_code # 123 on POSIX, unreachable on Windows Now if we do this explicitly, we could obtain the equivalent conventional exit code used to represent a non-existent file or command, and also an error will be printed to the console: `cmd.exe /v /c filedoesnotexist & exit !ERRORLEVEL!`
# 'filedoesnotexist' is not recognized as an internal or external command,
# operable program or batch file.
$?.exit_code # => 9009
Also, we are dealing with the shell's syntax here, which is beyond the scope of I'm not sure if turning |
That's not supposed to happen. 126 and 127 are reserved return codes under POSIX:
Source: https://tldp.org/LDP/abs/html/exitcodes.html |
@SamantazFox Yes, the meaning of these exit codes is clearly defined. That shouldn't be an issue. But the reference can be ambiguous. On windows, there's a clear indicator whether the specified shell command could be executed or not. Compare the result of these largely equivalent command invokations on Windows and POSIX: # Windows
Process.run("cmd /c NUL", shell: true).exit_code # => 1
Process.run("NUL", shell: true).exit_code # File::NotFoundError
# POSIX
Process.run("bash -c /dev/null", shell: true).exit_code # => 126
Process.run("/dev/null", shell: true).exit_code # => 126 |
Ah, hmm, I see. I'd expect exit code 126/127 to raise on POSIX systems anyway. |
Yes, the documentation is incorrect when using |
Process.run
withshell: true
behaves differently on Windows and POSIX platforms when thecommand
executable does not exist:Process::Status
with exit code127
(which indicates failure).FileNotFoundError
.Other error conditions might show similar inconsistent behaviour.
IMO raising
FileNotFoundError
is a more reasonable choice. The user asks to run a command and when that command doesn't even exist, this should usually be considered an error and raise. However, this might need to be considered a breaking change.Btw. in Ruby
`filedoesnotexist`
raises the exceptionErrno::ENOENT
on both Linux and Windows.The text was updated successfully, but these errors were encountered: