# Run a shell command with a pipe operator

**URL:** <https://forum.elixirforum.com/t/run-a-shell-command-with-a-pipe-operator/12662>\
**Category:** Questions\
**Tags:** erlang, troubleshooting\
**Created:** [February 21, 2018, 8:37am UTC](https://forum.elixirforum.com/t/run-a-shell-command-with-a-pipe-operator/12662 "2018-02-21T08:37:50Z")\
**Posts on this page:** 10\
**Page:** 1

<div class="post-metadata">

**Author:** ![tcoopman](https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/tcoopman/32/8112_2.png) [@tcoopman](https://forum.elixirforum.com/u/tcoopman)\
**Post date:** [February 21, 2018, 8:37am UTC](https://forum.elixirforum.com/t/run-a-shell-command-with-a-pipe-operator/12662/1 "2018-02-21T08:37:50Z")

</div>

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:

```elixir
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`:

```elixir
:os.cmd("sleep 0.1 | echo foo")

```

But whatever I do to execute this I get:

```elixir
: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 ([otp/lib/kernel/src/os.erl at master · erlang/otp · GitHub](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 ([os — OTP 29.0.2 (kernel 11.0.2)](http://erlang.org/doc/man/os.html))

---

<div class="post-metadata">

**Author:** ![tcoopman](https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/tcoopman/32/8112_2.png) [@tcoopman](https://forum.elixirforum.com/u/tcoopman)\
**Post date:** [February 21, 2018, 8:38am UTC](https://forum.elixirforum.com/t/run-a-shell-command-with-a-pipe-operator/12662/2 "2018-02-21T08:38:48Z")

</div>

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.

---

<div class="post-metadata">

**Author:** ![idi527](https://forum.elixirforum.com/letter_avatar_proxy/v4/letter/i/85e7bf/32.png) [@idi527](https://forum.elixirforum.com/u/idi527)\
**Post date:** [February 21, 2018, 8:40am UTC](https://forum.elixirforum.com/t/run-a-shell-command-with-a-pipe-operator/12662/3 "2018-02-21T08:40:43Z")

</div>

> [@tcoopman](#):
>
> :os.cmd(“sleep 0.1 | echo foo”)

Or `:os.cmd('sleep 0.1 | echo foo')`.

```elixir
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.

---

<div class="post-metadata">

**Author:** ![benwilson512](https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/benwilson512/32/1457_2.png) [@benwilson512](https://forum.elixirforum.com/u/benwilson512)\
**Post date:** [February 21, 2018, 11:59am UTC](https://forum.elixirforum.com/t/run-a-shell-command-with-a-pipe-operator/12662/4 "2018-02-21T11:59:14Z")

</div>

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.

---

<div class="post-metadata">

**Author:** ![alco](https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/alco/32/20034_2.png) [@alco](https://forum.elixirforum.com/u/alco)\
**Post date:** [February 21, 2018, 11:07pm UTC](https://forum.elixirforum.com/t/run-a-shell-command-with-a-pipe-operator/12662/5 "2018-02-21T23:07:29Z")

</div>

It is strange that `:os.cmd` accepts an atom for the command name, looks like a historical accident.

In general, functions from the Erlang standard library take character lists where in Elixir you would use a string. To make it more confusing, the Erlang type for such lists is called `string()`. I recommend taking a look at this [cheat sheet](https://elixir-lang.org/crash-course.html#lists-and-binaries) if you still feel confused.

Going back to your problem, Ben has already done a good job explaining the difference between Elixir’s `System.cmd` and Erlang’s `:os.cmd`. [In the source code](https://github.com/erlang/otp/blob/1540a0758b8d60af7b3832158015bd8cf64016af/lib/kernel/src/os.erl#L287-L313) for `:os.cmd` you can see it actually spawns a shell appropriate for the current OS and evaluates the string you’ve passed to the function in that shell.

Replicating this behaviour for your particular example using `System.cmd` is easy:

```elixir
System.cmd("sh", ["sleep 0.1 | echo foo"])

```

---

<div class="post-metadata">

**Author:** ![OvermindDL1](https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/overminddl1/32/2677_2.png) [@OvermindDL1](https://forum.elixirforum.com/u/OvermindDL1)\
**Post date:** [February 21, 2018, 11:19pm UTC](https://forum.elixirforum.com/t/run-a-shell-command-with-a-pipe-operator/12662/6 "2018-02-21T23:19:19Z")

</div>

> [@alco](#):
>
> It is strange that :os.cmd accepts an atom for the command name, looks like a historical accident.

Not entirely. A lot of the ‘base’ functions get the string value of atoms, it makes it cheap and efficient to pass around something like `sed` instead of having to do `"sed"` in the original erlang (plus it’s fantastic since atoms in erlang can have `@` in them without quoting too!). Calling other programs was generally used to access their stdin/stdout, not for argument parsing and ‘doing’ other stuff. 🙂

(Do note, the `sed` and `"sed"` above in erlang, in elixir would be `:sed` and `'sed'` respectively.)

---

<div class="post-metadata">

**Author:** ![Qqwy](https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/qqwy/32/1349_2.png) [@Qqwy](https://forum.elixirforum.com/u/Qqwy)\
**Post date:** [February 21, 2018, 11:37pm UTC](https://forum.elixirforum.com/t/run-a-shell-command-with-a-pipe-operator/12662/7 "2018-02-21T23:37:38Z")

</div>

> [@OvermindDL1](#):
>
> (plus it’s fantastic since atoms in erlang can have @ in them without quoting too!)

Why is this an advantage for calling functions that happen to also accept atoms and not only charlists?

---

<div class="post-metadata">

**Author:** ![OvermindDL1](https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/overminddl1/32/2677_2.png) [@OvermindDL1](https://forum.elixirforum.com/u/OvermindDL1)\
**Post date:** [February 21, 2018, 11:41pm UTC](https://forum.elixirforum.com/t/run-a-shell-command-with-a-pipe-operator/12662/8 "2018-02-21T23:41:36Z")

</div>

> [@Qqwy](#):
>
> Why is this an advantage for calling functions that happen to also accept atoms and not only charlists?

Overall less space for repeatedly used ‘strings’, atoms are essentially interned/flyweight’d strings after all (and lists of integers are anything but lightweight in memory, even if they are very fast iterables). Not really an issue nowadays, but Erlang is _old_ remember. ^.^

As for the `@` bit, it’s because they are used in areas on the VM such as server names, cookies, etc… Like in elixir you’d have to do `:"username@server"` where in erlang you’d just do `username@server`, nothing else needed, which is a great boon when manually doing a lot of work at the console or putting those in erlang config files. But of course, the ecosystem handles that better now and so things like Elixir don’t even support `@` in unquoted atoms unlike Erlang. ^.^;

---

<div class="post-metadata">

**Author:** ![tcoopman](https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/tcoopman/32/8112_2.png) [@tcoopman](https://forum.elixirforum.com/u/tcoopman)\
**Post date:** [February 24, 2018, 2:30pm UTC](https://forum.elixirforum.com/t/run-a-shell-command-with-a-pipe-operator/12662/9 "2018-02-24T14:30:05Z")

</div>

`System.cmd("sh", ["sleep 0.1"])` results in `/usr/bin/sh: sleep 0.1: No such file or directory {"", 127}`. So this solution doesn’t seem to work

---

<div class="post-metadata">

**Author:** ![alco](https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/alco/32/20034_2.png) [@alco](https://forum.elixirforum.com/u/alco)\
**Post date:** [February 24, 2018, 3:27pm UTC](https://forum.elixirforum.com/t/run-a-shell-command-with-a-pipe-operator/12662/10 "2018-02-24T15:27:18Z")

</div>

I made a mistake in the invocation. To evaluate a string in `sh`, the `-c` has to be passed first:

```elixir
System.cmd("sh", ["-c", "sleep 0.1"])

```
