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.