86

I want to execute a program through my Elixir code. What is the method to call a shell command to a given string? Is there anything which isn't platform specific?

7 Answers 7

112

Here is how you execute a simple shell command without arguments:

System.cmd("whoami", [])
# => {"lukas\n", 0}

Checkout the documentation about System for more information.

Sign up to request clarification or add additional context in comments.

Comments

17

System.cmd/3 seems to accept the arguments to the command as a list and is not happy when you try to sneak in arguments in the command name.

For example:

System.cmd("ls", ["-al"]) #works, while
System.cmd("ls -al", []) #does not.

What in fact happens underneath is System.cmd/3 calls :os.find_executable/1 with its first argument, which works just fine for something like ls but returns false for ls -al for example.

The Erlang call expects a char list instead of a binary, so you need something like the following:

"find /tmp -type f -size -200M |xargs rm -f" |> String.to_char_list |> :os.cmd

1 Comment

This behaviour is goof for security; if the string passed to System.cmd comes from an unsafe source, not using a shell to parse it closes some attack vectors.
12

You can have a look in the Erlang os Module. E.g. cmd(Command) -> string() should be what you are looking for.

2 Comments

Or System.cmd/1 from Erlang that works with Elixir strings. :)
There is another important difference between the two: stackoverflow.com/questions/22594988/…
9

The "devinus/sh" library is another interesting approach to run shell commands.

https://github.com/devinus/sh

1 Comment

Just FYI, this hasn't been updated in a couple years
5

I cannot link directly to the relevant documentation but it's here under the System module

cmd(command) (function) # 
Specs:

cmd(char_list) :: char_list
cmd(binary) :: binary
Execute a system command.

Executes command in a command shell of the target OS, captures the standard output of the command and returns the result as a binary.

If command is a char list, a char list is returned. Returns a binary otherwise.

Comments

0

One could also use erlang's :os module like so:

iex(3)> :os.cmd('time')
'\nreal\t0m0.001s\nuser\t0m0.000s\nsys\t0m0.000s\n'

Beware that you'll have to handle erlang binaries when processing the result :os.cmd('time') |> to_string() for example

1 Comment

Also, :os.cmd is quite different from System.cmd and more dangerous: it passes the string directly to the shell, which will interpret special characters such as *. Never call :os.cmd with variables provided from the outside. System.cmd does not use the shell and is therefore safer.
-1

If I have the following c program in the file a.c:

#include <stdio.h>
#include <stdlib.h>

int main(int arc, char** argv)
{

    printf("%s\n",argv[1]);
    printf("%s\n",argv[2]);

    int num1 = atoi(argv[1]);
    int num2 = atoi(argv[2]);

    return num1*num2;
}

and compile the program to the file a:

~/c_programs$ gcc a.c -o a

then I can do:

~/c_programs$ ./a 3 5
3
5

I can get the return value of main() like this:

~/c_programs$ echo $?
15

Similarly, in iex I can do this:

iex(2)> {output, status} = System.cmd("./a", ["3", "5"])
{"3\n5\n", 15}

iex(3)> status
15

The second element of the tuple returned by System.cmd() is the return value of the main() function.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.