Sod*_*hty 4 linux bash shell crystal-lang
我想在处理stdout和stderr输出时执行shell脚本.目前我使用Process.run,shell=false和stdin,stdout和stderr三个管道执行命令.我生成光纤以从stdout和stderr读取并记录(或以其他方式处理)输出.这对于单个命令非常有效,但对于脚本来说却非常糟糕.
我可以简单地设置shell=true调用时Process.run,但看看Crystal源代码似乎只是在命令行上加上"sh".我试过在"bash"前加上它并没有帮助.
重定向(>file)和管道(例如curl something | bash)之类的东西似乎不起作用Process.run
例如,要下载shell脚本并执行它,我尝试:
cmd =%{bash -c"curl http://dist.crystal-lang.org/apt/setup.sh "| 庆典}
Process.run(cmd,...)
bash添加了初始值,希望能够启用管道操作员.它似乎没有帮助.我也尝试分别执行每个命令:
script.split("\n").reject(/ ^#/,"").each {Process.run(...)}
但是,当命令使用重定向或管道时,仍然会失败.例如,该命令echo "deb http://dist.crystal-lang.org/apt crystal main" >/etc/apt/sources.list.d/crystal.list只输出:
"deb http://dist.crystal-lang.org/apt crystal main">/etc/apt/sources.list.d/crystal.list`
如果我使用``反引号执行方法,它可能会起作用; 但后来我无法实时捕获输出.
Jul*_*ier 11
问题是UNIX问题.父进程必须能够访问子进程的STDOUT.使用管道,您必须启动一个将运行整个命令的shell进程,包括| bash而不仅仅是curl $URL.在Crystal中这是:
command = "curl http://dist.crystal-lang.org/apt/setup.sh | bash"
io = MemoryIO.new
Process.run(command, shell: true, output: io)
output = io.to_s
Run Code Online (Sandbox Code Playgroud)
或者,如果您想复制Crystal为您做的事情:
Process.run("sh", {"-c", command}, output: io)
Run Code Online (Sandbox Code Playgroud)
我的理解基于阅读run.cr文件的源代码。该行为在处理命令和参数的方式上与其他语言非常相似。
如果没有shell=true, 的默认行为Process.run是使用命令作为可执行文件来运行。这意味着字符串需要一个程序的名字,不带任何参数,例如,uname将是一个有效的名称,因为我的系统上的程序调用uname在/usr/bin。
如果您曾经成功使用%{bash -c "echo hello world"}with shell=false,那么就有问题了——默认行为应该是尝试运行一个名为 的程序bash -c "echo hello world",这在任何系统上都不可能存在。
一旦你传入'shell=true',它就会执行sh -c <command>,这将允许像echo hello world命令一样的字符串工作;这也将允许重定向和管道工作。
该shell=true行为通常可以解释为执行以下操作:
cmd = "sh"
args = [] of String
args << "-c" << "curl http://dist.crystal-lang.org/apt/setup.sh | bash"
Process.run(cmd, args, …)
Run Code Online (Sandbox Code Playgroud)
请注意,我在这里使用了参数数组 - 如果没有参数数组,您无法控制参数如何传递到 shell。
之所以第一个版本,有或没有
shell=true不工作是因为管道是外面的-c,这是你要发送到的bash命令。