Skip to content

Commit d600406

Browse files
committed
Add :close_stdin to System.shell/2
It defaults to false as that was the behaviour in past Elixir versions. Closes #12135.
1 parent d84f889 commit d600406

File tree

3 files changed

+11
-4
lines changed

3 files changed

+11
-4
lines changed

lib/elixir/lib/system.ex

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -920,19 +920,26 @@ defmodule System do
920920
921921
## Options
922922
923-
It accepts the same options as `cmd/3`, except for `arg0`.
923+
It accepts the same options as `cmd/3` (except for `arg0`).
924+
It also accepts the following exclusive options:
925+
926+
* `:close_stdin` (since v1.14.1) - if the stdin should be closed
927+
on Unix systems, forcing any command that waits on stdin to
928+
immediately terminate. Defaults to false.
924929
"""
925930
@doc since: "1.12.0"
926931
@spec shell(binary, keyword) :: {Collectable.t(), exit_status :: non_neg_integer}
927932
def shell(command, opts \\ []) when is_binary(command) do
928933
assert_no_null_byte!(command, "System.shell/2")
934+
{close_stdin?, opts} = Keyword.pop(opts, :close_stdin, false)
929935

930936
# Finding shell command logic from :os.cmd in OTP
931937
# https://github.com/erlang/otp/blob/8deb96fb1d017307e22d2ab88968b9ef9f1b71d0/lib/kernel/src/os.erl#L184
932938
case :os.type() do
933939
{:unix, _} ->
934-
shell_path = :os.find_executable('sh') || :erlang.error(:enoent, [command, opts])
935-
command = "(#{command}\n) </dev/null"
940+
shell_path = :os.find_executable(~c"sh") || :erlang.error(:enoent, [command, opts])
941+
close_stdin = if close_stdin?, do: " </dev/null", else: ""
942+
command = IO.iodata_to_binary(["(", command, "\n)", close_stdin])
936943
do_cmd({:spawn_executable, shell_path}, [args: ["-c", command]], opts)
937944

938945
{:win32, osname} ->

lib/elixir/test/elixir/system_test.exs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -203,7 +203,7 @@ defmodule SystemTest do
203203

204204
@tag timeout: 1_000
205205
test "shell/1 returns when command awaits input" do
206-
assert {"", 0} = System.shell("cat")
206+
assert {"", 0} = System.shell("cat", close_stdin: true)
207207
end
208208

209209
test "shell/1 with comment" do

0 commit comments

Comments
 (0)