1

I've spotted something that I find very puzzling about the behavior of System.cmd. I just wanted to ask if anyone might have thoughts on what I may be doing wrong or what may be going on.

I've been trying to wrap an Elixir script around the ack programmer's grep. I tried this:

{_message, errlevel} = System.cmd("ack",[])

And I get back the help text that ack displays on an empty command line; I won't bother to reproduce it here because it's not necessarily germane to the question.

Then I try this:

{_message, errlevel} = System.cmd("ack",[""])

And it looks like iex hangs. Now I realize in the first case the output may be going to stderr rather than stdout. But there's another reason I'm asking about this; I found something even more interesting to me. Because I'm not 100% committed to using ack I thought I'd try ripgrep on the thought that it might interact with stdout better.

So if I do this:

{_message, errlevel} = System.cmd("rg",[])

Same as ack with no arguments--shows me the help text. Again I'm guessing it's probably out to stderr. I could check to confirm my assumption but what's even more interesting to me is that when I do this:

{_message, errlevel} = System.cmd("rg",[""])

It hangs again!

I had always figured the issue is with how ack interacts with stdout but now I'm not so sure since I see the same behavior with ripgrep. This is Elixir 1.13.2 on MacOSX 13.1. I've seen this same behavior with older versions of MacOSX.

Any idea how I can get the ack and/or ripgrep process to terminate so I get a response back? I've seen this https://hexdocs.pm/elixir/main/Port.html#module-zombie-operating-system-processes and I can try it but I was hoping for something slightly less hacky, I guess. Any suggestions? Also if I use the :stderr_to_stdout option set to true, it doesn't seem to make any difference.

I've seen this Q & A but I'm not totally clear on how using Task.start_link would help in this case. I mean would one do a Task.start_link on System.cmd?

Adam Millerchip
  • 20,844
  • 5
  • 51
  • 74
Onorio Catenacci
  • 14,928
  • 14
  • 81
  • 132
  • 1
    Interesting; it completely hangs the shell. Even if I start another job (^G, s, c), that one's hung as well. – Roger Lipscombe Jan 06 '23 at 20:32
  • 2
    I _suspect_ that System.cmd is wiring stdin up with something that never provides any data, and `rg` is attempting to read from that. So it hangs -- in `System.do_port` in my testing. – Roger Lipscombe Jan 06 '23 at 20:41
  • 1
    Same thing happens with `System.cmd("cat", [])`. Looks like a bug in Elixir. – Roger Lipscombe Jan 06 '23 at 20:43
  • This is a case where I took out too much detail. I meant to make a minimal example and I removed too much. There's an issue here but I need to draft another question that better demonstrates what I'm trying to do. ack and ripgrep are not awaiting input from STDIN--at least not in what I'm trying to figure out anyway. – Onorio Catenacci Jan 09 '23 at 14:25

2 Answers2

2

You are executing a command that expects input on STDIN, but with System.cmd/3, there is no mechanism to provide the input.

Elixir has no way to know the behaviour of the command you are executing, so waits for the process to terminate, which never happens. As José mentioned on the issue Roger Lipscombe raised, this is expected behaviour.

If you want to send the OS process input via STDIN, you need to use Ports. However, there are limitations there too, which I asked about here.

For ack specifically, it reads from STDIN if you don't provide a filename. So you can workaround the limitation by putting the data in a file, and providing the filename as an argument, rather than piping the data via OS streams.

Adam Millerchip
  • 20,844
  • 5
  • 51
  • 74
  • This is a case where I took out too much detail. I meant to make a minimal example and I removed too much. There's an issue here but I need to draft another question that better demonstrates what I'm trying to do. ack and ripgrep are not awaiting input from STDIN--at least not in what I'm trying to figure out anyway. – Onorio Catenacci Jan 09 '23 at 14:25
1

Looks like a bug. I've filed https://github.com/elixir-lang/elixir/issues/12321.

Roger Lipscombe
  • 89,048
  • 55
  • 235
  • 380