I am trying to pass command-line arguments to my elixir release. I have built the release using
MIX_ENV=prod mix release
Now, Am not able to pass any command-line arguments with the start command.
_build/prod/rel/prod/bin/prod start arg1 arg2
Using eval i have achieved passing the arguments but it stops after a while.
_build/prod/rel/prod/bin/prod eval "Hello.nodes([3, :node1])"
Is there any way that I can pass the args through the start flag?
Using eval i have achieved passing the arguments but it stops after a
while.
_build/prod/rel/prod/bin/prod eval "Hello.nodes([3, :node1])"
From the docs:
The eval command starts its own instance of the VM but without
starting any of the applications in the release and without starting
distribution. For example, if you need to do some prep work before
running the actual system, like migrating your database, eval can be a
good fit. Just keep in mind any application you may use during eval
has to be explicitly loaded and/or started.
I'm guessing that your eval tries to use an application that you didn't explicitly load before executing the eval.
Is there any way that I can pass the args through the start flag?
It's not documented, but there are various ways to configure a release:
https://elixir-lang.org/getting-started/mix-otp/config-and-releases.html
Maybe an escript would be a better fit?
escript provides support for running short Erlang programs without
having to compile them first, and an easy way to retrieve the
command-line arguments.
It is possible to bundle escript(s) with an Erlang runtime system to make it self-sufficient and relocatable.
After using "Source installation on macOS" to install drake, "Bazel built//..." and " Bazel test//..." are done. The question is: how I run an example , for examples/acrobot/run_swing_up ? Should I input a command like: Bazel-bin/examples/acrobot/run_swing_up ?
Yup, you can either run it via bazel run or ./bazel-bin (the latter being better for running multiple processes, having stdin access, etc.):
https://drake.mit.edu/bazel.html
Some of the examples also have brief READMEs or docs on how to run it; e.g.:
jaco arm
inclined plane
Say I have a simple python script which executes an elixir/erlang script using the subprocess module.
Say the OS PID of the python script is P1 and that of the spawned elixir/erlang script running is P2.
I want to know if communication between P1 and P2 is possible. More specifically, P1 writes something to the stdin of P2, and P2 reads the received input from P1 and writes some corresponding output to its own stdout and P1 reads from the stdout of P2 and again writes something to the stdin of P2 and so on.
I know the other way is possible, i.e., spawning external process from inside elixir/erlang and then communicating with the process. Any help appreciated, thanks.
Yep, this sort of cross-language IPC is entirely possible. The vast majority of the documentation and blog posts and such (and the responses so far here on StackOverflow!) assume the opposite of what you seem to be asking - that is, they assume that Erlang/Elixir is spawning the Python subprocess, rather than Python spawning an Erlang/Elixir subprocess. If that's okay (i.e. you're okay with your Erlang or Elixir app spinning up the Python process), then great! Badu's answer will help you do exactly that, and you could also have a gander at the documentation for Elixir's Port module for an extra reference.
But that doesn't seem to be the answer you seek, and that's less fun. The world needs more documentation on how to go the other way around, so let's dive into the wonderful world of running Erlang as a subprocess of a Python script!
First, our Python script (eip.py):
#!/usr/bin/env python
from subprocess import Popen, PIPE
erl = Popen(['escript', 'eip.escript'],
stdin=PIPE, stdout=PIPE, stderr=PIPE)
ping = input('Ping: ')
outs, errs = erl.communicate(input=ping.encode('utf-8'),
timeout=15)
print(outs.decode('utf-8'))
On the Erlang side (as you might've noticed in that Python code), a really easy way to go about this is to use the escript program, which allows us to write more-or-less self-contained Erlang scripts, like this here eip.escript:
#!/usr/bin/env escript
main(_Args) ->
Ping = io:get_line(""),
io:format("Pong: ~ts", [Ping]).
Now, when you run python3 eip.py and enter asdf at the Ping: prompt, you should get back Pong: asdf.
Doing the same thing with Elixir is only slightly more complicated: we need to create a Mix project with a bit of extra configuration and such to tell Mix to put together an escript file. So let's start with the project:
$ mix new eip
* creating README.md
* creating .formatter.exs
* creating .gitignore
* creating mix.exs
* creating lib
* creating lib/eip.ex
* creating test
* creating test/test_helper.exs
* creating test/eip_test.exs
Your Mix project was created successfully.
You can use "mix" to compile it, test it, and more:
cd eip
mix test
Run "mix help" for more commands.
(It's probably overkill to even use Mix for this simple example, but I'm assuming you'll eventually want to do something more advanced than this example)
Next, you'll want to add an escript option to your mix.exs, like so:
defmodule Eip.MixProject do
use Mix.Project
def project, do: [
app: :eip,
version: "0.1.0",
elixir: "~> 1.9",
start_permanent: Mix.env() == :prod,
deps: deps(),
escript: escript()
]
def application, do: [extra_applications: [:logger]]
defp deps, do: []
defp escript, do: [main_module: Eip]
end
And finally, your lib/eip.ex module:
defmodule Eip do
def main(_argv) do
ping = IO.gets("")
IO.puts("Pong: #{ping}")
end
end
And now we just need to build it:
$ mix escript.build
Compiling 1 file (.ex)
Generated eip app
Generated escript eip with MIX_ENV=dev
eip.py will need a slight adjustment to point to this new Elixirified ping/pong IPC thingamabob:
#!/usr/bin/env python
from subprocess import Popen, PIPE, TimeoutExpired
erl = Popen(['escript', 'eip/eip'],
stdin=PIPE, stdout=PIPE, stderr=PIPE)
ping = input('Ping: ')
outs, errs = erl.communicate(input=ping.encode('utf-8'))
print(outs.decode('utf-8'))
Unfortunately, this doesn't entirely work:
$ python3 eip.py
Ping: asdf
Pong: eof
The same results happen even when using a more direct port of the Erlang version (i.e. replacing IO.gets("") with :io.get_line("") and IO.puts("Pong: #{ping}") with :io.fwrite("Pong: ~ts", [ping]), which means something specific to Elixir's STDIN handling in general is causing it to prematurely believe it's reached end-of-file. But hey, at least one direction works!
Like Dogbert said, you can use Ports instead. Check out Erlport
and here is a blog post on communicating between Elixir and Python
Let's say I have a Dart script called dart-test. I would like to distribute this script and make it so that users just have to put it in a folder in their $PATH, and execute it from anywhere just by typing dart-test in their terminal.
For the sake of this question, let's pretend I am the user test on my machine. I am on Mac OS X and installed the Dart binary with Homebrew. The dart binary lies in /home/test/.brew/bin and is in the $PATH.
Consequently, the following works:
$ cat <<HEREDOC > ~/.brew/bin/dart-test
#!/home/test/.brew/bin/dart
main() => print('Dart shebang works!');
HEREDOC
$ chmod u+x ~/.brew/bin/dart-test
$ dart-test
Dart shebang works!
The problem is that the Dart shebang I use is not portable, my script won't work on any other computer than mine. Is there a portable way to do this?
(Considering Dart is kind of like Python and Ruby in the way it executes, I just looked at the standard way of doing it in those two languages. The env binary.)
#!/usr/bin/env dart
Seems to be the way. It will look for dart binaries in the user's environment, and apparently enables simple Dart scripts to be executed from anywhere, provided the Dart VM is installed and in the $PATH.
I would like to inherit environment variables in GNU Parallel. I have several 'scripts' (really just lists of commands, designed for use with GNU Parallel) with hundreds of lines each that all call different external programs. However, these external program (out of my control) requires that several environment variables be set before they will even run.
Setting/exporting them locally doesn't seem to help, and I don't see any way to add this information to a profile.
The documentation doesn't seem to have anything this, and similar SO pages suggest wrapping the command in a script. However, this seems like an inelegant solution. Is there a way to export the current environment, or perhaps specify the required variables in a script?
Thanks!
This works for me:
FOO="My brother's 12\" records"
export FOO
parallel echo 'FOO is "$FOO" Process id $$ Argument' ::: 1 2 3
To make it work for remote connections (through ssh) you need to quote the variable for shell expansion. parallel --shellquote can help you do that:
parallel -S server export FOO=$(parallel --shellquote ::: "$FOO")\;echo 'FOO is "$FOO" Process id $$ Argument' ::: 1 2 3
If that does not solve your issue, please consider showing an example that does not work.
-- Edit --
Look at --env introduced in version 20121022
-- Edit --
Look at env_parallel introduced in 20160322.