I want to execute a shell script while handling stdout and stderr output. Currently I execute commands using Process.run
, with shell=false
and three pipes for stdin, stdout and stderr. I spawn fibers to read from stdout and stderr and log (or otherwise process) the output. This works pretty well for individual commands, but fails horribly for scripts.
I could simply set shell=true
when calling Process.run
, but looking at the Crystal source it seems that merely prepends "sh" to the commandline. I've tried prepending "bash" and it didn't help.
Things like redirection (>file
) and pipes (e.g. curl something | bash
) don't seem to work with Process.run
For example, to download a shell script and execute it, I tried:
cmd = %{bash -c "curl http://dist.crystal-lang.org/apt/setup.sh" | bash}
Process.run(cmd, ...)
The initial bash
was added in the hope that it would enable the pipe operator. It doesn't seem to help. I also tried executing each command separately:
script.split("\n").reject(/^#/, "").each { Process.run(...) }
But of course, that still fails when a command uses redirection or pipes. For example, the command echo "deb http://dist.crystal-lang.org/apt crystal main" >/etc/apt/sources.list.d/crystal.list
simply outputs:
"deb http://dist.crystal-lang.org/apt crystal main" >/etc/apt/sources.list.d/crystal.list`
It might work if I used the ``
backticks method of execution instead; but then I wouldn't be able to capture the output in real time.
bash -c
in the first case to get it to invoke. You're fighting againstshell=false
, though, which is the thing that would allow you to use shell syntax directly. – Denunciateshell=true
doesn't help any. – Citystatebash -c
call seems to work, however. So...why doesn'tshell=true
work? Surely it's pretty much the same thing? – Citystate