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

RSP87
I’m working on a project that simulates the bumbl example in the programming phoenix book. It acts almost like an email client. We have a...
New
nseaSeb
Hello, I know there is an approach for handling lists that allows for optimized traversal, but I can’t recall the specific method (somet...
New
brecabral
Documentation While reading the Scoped Routes section, I noticed that the documentation currently refers to a problem without explainin...
New
kpanic
Hi everyone, I am toying with the idea of building a “match maker” for giving personal help to people that wants to start coding. I sta...
New
velrest
So my question is quite simple and i have found no conclusive answer on forum, google or AI. Should we use :erlang.float for Integer to ...
New
asweet-confluent
I recently noticed that Elixir’s Logger defaults its primary log level to :debug when no :logger, :level application configuration is pre...
New
apz
I’m new to elixir and just tried to install the elixirLS extension for VScode(ium) and it is throwing some errors that I would like help ...
New

Other Trending Topics Top

GenericJam
Edit: 2026 May 15 - This post is archived. Mob is alive!! Main docs: mob v0.7.11 — Documentation A bit of explanation for the slightly c...
New
JesseHerrick
Hey, I’m Jesse and I’m the main contributor behind Dexter, a full-featured, lightning-fast Elixir LSP optimized for large codebases. It s...
New
mudasobwa
I am happy to introduce the very α version of the new programming language compiled to BEAM. Welcome Cure. It has literally three kille...
New
garrison
Hobbes is a low-level distributed database for the Elixir programming language. Hobbes provides a simple, safe, and scalable storage lay...
New
marciok
Hi there! We created Gust: A task orchestrator inspired by Airflow. For those who have never heard about Aiflow, it’s a Python-based wor...
New
mhanberg
Hi everyone! The first release candidate for the Expert language server project is now available! We’ve published a press release detai...
New

We're in Beta

About us Mission Statement

Options

Thread Display Mode




Thread Preview

Skip Thread Previews