65.9K
CodeProject 正在变化。 阅读更多。
Home

集成 ShellScript 与 R 混合编程指南

starIconstarIconstarIconstarIconemptyStarIcon

4.00/5 (1投票)

2014年10月26日

CPOL

5分钟阅读

viewsIcon

11206

downloadIcon

67

将 R 脚本与我的 shellscript 结合起来的想法非常棒,通过将 shellscript 与 R 混合编程,可以扩展我的脚本功能,而且我可以在一个脚本文件中同时使用这两种编程语言。太不可思议了,对吧?

下载 ShellScript 混合 R 脚本示例源代码

简介与背景

VisualBasic Shellscript (vbss) 语言是我为调试我的虚拟细胞程序引擎开发的科学研究工具,但现在它只有很少的扩展包。所以,我决定通过混合编程特性来扩展 shellscript 功能,现在 CPAN 上有许多 R 包可用于 ShellScript!太棒了! 

注意:有关 VisualBasic Shellscript 编程语法的更多详细信息,您可以查阅本文档

引用
ShellScript 最初是为了调试我的“基因组即代码”虚拟细胞模拟引擎而开发的,但现在它已成为 .Net 程序的脚本语言。
 

目前,由于 R 语言的开源和数学统计语言特性,大多数生物科学研究算法和研究工具都是用 R 语言实现的,R 语言是研究工作中最重要的工具。将 R 脚本与我的 shellscript 结合起来的想法非常棒,通过将 shellscript 与 R 混合编程,可以扩展我的脚本功能,而且我可以在一个脚本文件中同时使用这两种编程语言。太不可思议了,对吧?

使用代码

ShellScript 外部脚本脚本语言环境入口点接口

为了支持与其他脚本语言的混合动态脚本,并使 shellscript 更具可扩展性,我在 shellscript 解释器中添加了混合编程功能。

您需要在您的 shellscript API 库上实现两个自定义属性,您可以将这些自定义属性视为 .NET 语言中的接口。

  1. 命名空间入口点 (ScriptEntryPoint)
  2. 方法指针处理程序接口 (ScriptEntryInterface)

 

ShellScript 中混合脚本的语言语法

  1. 附加脚本环境
!<EntryName>
  1. 与外部脚本语言进行混合脚本
Syntax for calling external script: 
[Shellscript_variable] << [hybrids_script]

Syntax for assign the variable in the external script environment: 
[ShellScript_variable] >> [hybrids_script_variable]

 

使用 ShellScript 和 R 语言进行混合编程

ShellScript 和 R 语言的混合编程最初是在 **RDotNET** 项目上开发的,该项目由 **hmansell 和 jperraud** 开发。您可以在本文的附件文件中找到 **RDotNET** 的源代码。

Codeplex 上的 RDotNET 项目:[^] http://rdotnet.codeplex.com/

Shellscript 的 RDotNET API 在 `RDOTNET.Extensions.ShellScriptAPI` 项目中定义,您可以在类源文件 **API.vb** 中看到所有实现细节。然后,您可以将此项目用作模板示例,为其他脚本语言创建混合编程。

以下是为我的 shellscript 开发混合脚本接口 API 的步骤:

  1. 在 API 项目中定义脚本环境入口点,此步骤很简单,只需将 `Microsoft.VisualBasic.ShellScript.HybridsScripting.ScriptEntryPoint` 自定义属性放在您的 API 模块类上,并指定一个脚本类型名称。示例如下:
<Microsoft.VisualBasic.ShellScript.HybridsScripting.ScriptEntryPoint("R.NET")>
<[Namespace]("r.net")>
Public Module API
……
End Module
  1. 实现脚本入口点接口,在此步骤中,您需要实现三个接口:`init`、`setvalue` 和 `evaluate`(`init` 用于初始化混合脚本环境,`setvalue` 和 `evaluate` 接口用于 shellscript 和混合脚本环境之间的数据交换)。这些接口通过自定义属性实现,您可以在 `Microsoft.VisualBasic.ShellScript.HybridsScripting` 命名空间中找到。

以下是三个接口的实现示例:

首先,需要 `init` 来初始化混合脚本语言和 shellscript 之间的脚本环境,此自定义属性所属的方法是一个无参数参数方法。如果脚本环境不需要初始化,则可以留空此方法,但仍需要声明一个空方法。以下是为在 shellscript 中编写 R 环境进行脚本编写的示例:

Dim REngine As RDotNET.REngine

<Microsoft.VisualBasic.ShellScript.HybridsScripting.ScriptEntryInterface(ShellScript.HybridsScripting.ScriptEntryInterface.InterfaceTypes.EntryPointInit)>
<Command(".init_r_dotnet()")> Public Function Init() As RDotNET.REngine
    REngine = RDotNET.REngine.CreateSession
    Return REngine
End Function

其次,然后您可以实现脚本语言的 `evaluate` 接口。**此接口应有一个字符串类型的参数来接收脚本文本,并返回一个对象。**以下是 R 脚本入口接口实现的示例:

<Microsoft.VisualBasic.ShellScript.HybridsScripting.ScriptEntryInterface(ShellScript.HybridsScripting.ScriptEntryInterface.InterfaceTypes.Evaluate)>
Public Function Evaluate(scriptLine As String) As Object
    Return REngine.Evaluate(statement:=scriptLine)
End Function

最后,还需要一个将 .NET 对象传递到混合脚本环境的接口。在此方法中,需要两个参数:`第一个参数是用于混合脚本环境中变量的名称,第二个参数是变量的值`。您应该始终考虑脚本环境是否支持 .NET 对象,如果不支持,则应在传递变量对象之前实现数据类型转换操作。

<Microsoft.VisualBasic.ShellScript.HybridsScripting.ScriptEntryInterface(ShellScript.HybridsScripting.ScriptEntryInterface.InterfaceTypes.SetValue)>
Public Function SetSymbol(Variable As String, value As Object) As Boolean
    Try
        Call Engine.SetSymbol(Variable, value)
    Catch ex As Exception

        Return False
    End Try

    Return True
End Function

因此,只需三个简单的步骤,您就可以为 R 和 shellscript 语言实现混合编程接口。

 

混合脚本测试

混合脚本 shellscript 文件可在 shellscript 调试目录中找到,以下是用于测试的脚本文本:

imports r.net

# telling the shellscript runtime mount the R scripting entrypoints

!r.net

# integerated the R script with shellscript, if successful interacting with R, then a new text file will be make in the save directory!

# test1:  r function invoke
r << data <- read.csv("./test_.csv")
r << write.csv(data, "./test___successfully.txt")

# get the return value of the r function
call $r -> cowsay

# test2: variable setting into the r enviroment
v <- array.new 1,2,3,4,5,6,7,8,9,10
v <- $v -> integervector
v2 <- array.new 1,3,4,5,6,7,8,9,4,3,2,2
v2 <- $v2 -> integervector

mat <- array.new \$v2,\$v2
mat <- $mat -> data.frame

#verify that the variable is passing into the R enviroment successfully!
$mat >> mat
r << write.csv(mat, "./matrix_test_successfully.txt")
$v >> v
v << write.csv(v, "./vector_test_successful.txt")

call "ALL TEST OK!!!" -> msgbox title "test ok!!!"

 

脚本运行详情
 

  1. 初始化混合脚本挂载点

# telling the shellscript runtime mount the R scripting entrypoints
!r.net

脚本被解析为混合脚本环境初始化入口点

初始化语句的语法是`语句应以 ! 字符前缀开头,然后后面的字符串是脚本环境注册名称`。因此,解析过程可以描述如下:

If Command.First = "!" Then 'Mount the hybrid programming entry point.(挂载混合编程的脚本环境的执行载入点)

      Dim Name As String = Mid(Command, 2).Trim

      Return New Runtime.Objects.ObjectModels.ShellScript.CodeLine With {
           .LineNumber = LineNumber, .LineFlag = LineNumber, .OrignialScriptLine = Command,
           .VariableAssigned = "$",
           .Method = Function() _ShellScriptHost.AttachesEntryPoint(Name)}
End If
  1. 求值和设置值测试

您应始终记住**使用 << 运算符来求值外部混合脚本**,如果脚本没有返回值,则将返回 null 值。

# integerated the R script with shellscript, if successful interacting with R, then a new text file will be make in the save directory!

# test1:  r function invoke

r << data <- read.csv("./test_.csv")
r << write.csv(data, "./test___successfully.txt")

# get the return value of the r function
call $r -> cowsay

这是语法解析代码:

'invoke the external hybrid programming script statement and get the return value.(调用外部的脚本并返回计算结果)
If InStr(Command, " << ") > 0 Then
    Dim ExternalScript As String = Command.Replace(VariableName, "").Trim

    VariableName = VariableName.Replace(" << ", "").Trim
    GetValue = Function() _ShellScriptHost.ExternalScriptInteropEvaluate(ExternalScript)
    Return New Runtime.Objects.ObjectModels.ShellScript.CodeLine With {
         .LineNumber = LineNumber, .LineFlag = LineNumber,
         .VariableAssigned = VariableName,
         .OrignialScriptLine = OriginalCommand,
         .Method = GetValue}
End If

**当您想将 shellscript 变量传递到混合脚本环境时,您可以使用 >> 运算符来完成此操作。**(如果脚本环境支持 .NET 类型,则可以直接传递对象值,否则,您应将 .NET 对象类型转换为脚本支持的类型)。

以下是将 .NET 整数向量作为数据帧对象传递到 R 的示例。由于 R 不支持 .NET 对象类型,因此在将变量推送到 R 环境之前,使用 `integervector` 函数实现了数据类型转换操作。

v2 <- $v2 -> integervector

mat <- array.new \$v2,\$v2
mat <- $mat -> data.frame

#verify that the variable is passing into the R enviroment successfully!

$mat >> mat
r << write.csv(mat, "./matrix_test_successfully.txt")

这是解析推送变量语法的代码:

' Pushing the .NET variable into the hybirds scripting environment
If InStr(Command, " >> ") > 0 Then
     Dim Test As String = "$" & VariableName

     If InStr(Command, Test) >= 1 Then
          VariableName = Test
     End If

     Dim ExternalScriptVariable As String = Command.Replace(VariableName, "").Trim
     VariableName = VariableName.Replace(" >> ", "").Trim
     GetValue = Function() _ShellScriptHost.ExternalScriptInteropSetValue(ExternalScriptVariable, _ShellScriptHost._HostMemory.TryGetValue(VariableName))

     Return New Runtime.Objects.ObjectModels.ShellScript.CodeLine With {
          .LineNumber = LineNumber,
          .LineFlag = LineNumber,
          .VariableAssigned = VariableName,
          .OrignialScriptLine = OriginalCommand,
          .Method = GetValue}
End If

现在,让我们启动 shellscript 程序,并使用 `source` 命令调用调试目录中的 `R_test.txt` 脚本文件,以测试混合编程脚本。测试结果已显示在下方(您需要在运行此脚本之前安装 R 程序),哒哒哒......

© . All rights reserved.