zapateo

zapateo

Hi everyone, this is my first post on this forum :slight_smile:
I am learning Elixir and I wish to write my software/scripts with it, I really love the syntax.
One problem I encountered is launching a system command and interact with it through stdin/stdout.
For example something like:

System.cmd("sudo", ["whoami"])
System.cmd("vi", [])

doesn’t work at all because they require access to stdin/stdout (seems like they can’t find a tty).
I searched a lot on the web and I found some resources with some workaround (eg. using a GUI askpass for sudo or launching system commands in another terminal); such resources I have found are a bit old.

My question is: is the situation changed? Is there any way, for example using Ports, to make the commands above work “as expected” like in other programming language?

For example in Python I write:

import subprocess
subprocess.run("vi")

This is the only “missing feature” that prevents me from porting all my software and scripts to Elixir.

Thanks in advance :slight_smile:

Showing Posts 1 to 7

NobbZ

NobbZ

I know that sudo doesn’t even use stdin/stdout but reads from the (virtual) tty directly. I assume similar for vi.

To be honest, I wouldn’t even expect your python code to work…

And why port everything to Elixir? If you already have scripts in python that do their job, then keep them that way… I still prefer using zsh and python for doing scripts that I run from the terminal or via cron.

I use Elixir mainly for long running and daemon style applications.

benwilson512

benwilson512

Author of Craft GraphQL APIs in Elixir with Absinthe

Hi @zapateo, you may want to check out Porcelain – porcelain v2.0.3, it has a spawn function that should be relatively easy to use for something like this.

I do agree with @NobbZ overall with respect to this idea though. Use the right tool for the right job. If you already have functioning python scripts for this stuff and there isn’t internal concurrency issues that a port to Elixir would provide clear wins with, I’d consider whether a port like this provides value. If you want to do it for educational reasons then that’s perfectly fine, but if you’re trying to solve problems, consider whether the problem is a good fit for what you have or a better fit with Elixir.

outlog

outlog

+1 on porcelain, though check out GitHub - jayjun/rambo: Run your command. Send input. Get output. · GitHub as well, as I believe that supersedes porcelain.. (I have only ever used porcelain few years back to do some pdf scraping..)

zapateo

zapateo OP

Thanks for your replies, guys! :slight_smile:

I tried both porcelain and rambo, they both look really cool for running system
processes/shell commands, but the problem still persist:

iex(1)> Porcelain.shell("vi")
Vim: Warning: Output is not to a terminal
Vim: Warning: Input is not from a terminal

Anyway, thanks for the feedback about choosing the right tool for the right job.
Porting my software in Elixir has started just for learning purposes but ended
in an overcomplicated mission.

LostKobrakai

LostKobrakai

I’m not sure about the “not a terminal” problem, but usually if you want to continuously interact with an external program though stdin/stdout you should go for erlexec instead of rambo/porcelain.

jayjun

jayjun

I do like Elixir as a scripting language except the BEAM is notoriously bad at working with external commands, even worse when those require the terminal.

For starters, this works.

port = Port.open({:spawn, "vi"}, [:nouse_stdio, :exit_status])

receive do
  {^port, {:exit_status, exit_status}} -> IO.puts "vi exited with #{exit_status}"
end

But ports are really designed to work with external programs custom tailored for your Erlang app.

One assumption is Erlang must talk to your external process, so pipes are connected to the child’s standard input/output. :nouse_stdio means “use file descriptors 3 and 4 instead” so vi inherits the terminal as standard input/output and things work as expected. System.cmd—which is simply a convenience wrapper around ports—won’t work because it is hardcoded to :use_stdio.

Next, Port.open does not block like subprocess.run. To mimic that, you can ask for the :exit_status then block with receive.

Finally, child processes spawned by Erlang ports are detached from the controlling terminal. So programs that read from the terminal directly like sudo won’t work. There’s no general workaround, only application-specific ones.

As you can see, it’s an uphill battle but keep in mind that Python is first and foremost a scripting language. If you don’t need to call external programs, .exs files and escripts are a pleasant way to automate. Otherwise, libraries can help ease some hurdles but not entirely.

zapateo

zapateo OP

Thanks a lot. Your answer clarified to me many aspects of the problem.

Also, the snippet you posted works as expected; so simple but very powerful, that it what I was looking for.

:slight_smile:

— All posts loaded —

Where Next? Top

Trending in Questions Top

stjefim
Hello! Suppose you are building workflow (order / task / payment) processing system with the following requirements: Each workflow con...
New
Blokh
Hey guys, I’ve got a huge CSV ( around 10 GB ) that needs to be processed hourly Do you guys have any suggestions what is the best prac...
New
kszambelanczyk
Hello! Could someone please give me a help/sample code, how to delete a file from s3 using waffle/waffle_ecto from Phoenix app. I creat...
New
Onor.io
I have what I’ve heard referred to as a “lookup table” in my database. This is a way of assigning codes to common values. One common lo...
New
jaybe78
Hello, I’m developing a online persistent chat system (what’s app) like using elixir/dynamodb/aws for a mobile app(flutter). The diffic...
New
Trolleger
What approach to take when sending live updates to “random” users Hi! I have a question, I have a little chat app, and when I create a DM...
New
widianto
I think I’ve found a small improvement I could contribute to <%= web_namespace %>.CoreComponents (installer/templates/phx_web/compo...
New

Other Trending Topics Top

garrison
Hobbes is a low-level distributed database for the Elixir programming language. Hobbes provides a simple, safe, and scalable storage lay...
New
mcass19
ExRatatui lets you cook up rich terminal UIs in Elixir, powered by Rust’s ratatui via Rustler NIFs. Build interactive terminal applicatio...
New
Damirados
Hello everyone. After busy few months I am happy to announce v0.1.0 of Emerge & Solve. They are GUI (Emerge) and State management (S...
New
netoum
Corex is an accessible, unstyled UI component library for Phoenix that integrates Zag.js state machines using Vanilla JavaScript and Live...
New
wintermeyer
There are three potential reasons for members of this forum to have a look at https://vutuv.de You are tired or annoyed of LinkedIn. Yo...
New
webofbits
Aludel - LLM Evaluation Workbench Aludel is an embeddable Phoenix LiveView dashboard for evaluating and comparing LLM prompts across mult...
New

We're in Beta

About us Mission Statement

Options

Thread Display Mode




Thread Preview

Skip Thread Previews