tcoopman
Run a shell command with a pipe operator
I’m trying to run a shell command with a pipe operator in it. For example “sleep 0.1 | echo foo”. At first I tried to do this with System.cmd:
System.cmd("sleep", ["0.1", "|", "echo", "foo"])
But this results in /usr/bin/sleep: invalid time interval '|', invalid time interval 'echo'....
So next I tried to use :os.cmd:
:os.cmd("sleep 0.1 | echo foo")
But whatever I do to execute this I get:
:os.cmd("sleep 0.1 | echo foo")
** (FunctionClauseError) no function clause matching in :os.validate/1
The following arguments were given to :os.validate/1:
# 1
"sleep 0.1 | echo foo"
(kernel) os.erl:281: :os.validate/1
(kernel) os.erl:237: :os.cmd/1
Looking into the code of :os (https://github.com/erlang/otp/blob/master/lib/kernel/src/os.erl) is see that :os.validate expects atoms? But in the erlang docs there are no atoms used (http://erlang.org/doc/man/os.html)
Marked As Solved
tcoopman
I’ve just been able to solve my own problem.
If I do: os.cmd(:"sleep 0.1 | echo foo") it works.
So I need to pass an atom to os.cmd.
Also Liked
alco
I made a mistake in the invocation. To evaluate a string in sh, the -c has to be passed first:
System.cmd("sh", ["-c", "sleep 0.1"])
idi527
Or :os.cmd('sleep 0.1 | echo foo').
iex(1)> :os.cmd('sleep 0.1 | echo foo')
'foo\n'
It works with atoms and character lists. Doesn’t seem to work with binaries.
I would try to avoid creating new atoms for each command you might want to run since they are not garbage collected.
benwilson512
System.cmd does not run a shell, so pipes, redirects, and so on aren’t supported. System.cmd is basically the closest thing that Elixir has to fork.
:os.cmd is definitely handy, but take great care if any of the stuff in your command comes from users (like filenames). You risk letting users run arbitrary programs.








