Click here to Skip to main content
15,880,392 members
Articles / High Performance Computing / Parallel Processing

Powerful ShellScript for bioinformatics researchers

Rate me:
Please Sign up or sign in to vote.
5.00/5 (7 votes)
14 Oct 2014GPL316 min read 15.3K   114   9  
The ShellScript is originally developed for the debugging of my "genome-in-code" virtual cell simulation engine, but now it becomes a script language for a .Net program.
 
Download ShellScript Source Code

Introduction & Background

The ShellScript is originally developed for the debugging of my GCModeller virtual cell simulation engine, but now it becomes a script language for a .Net program. As my genome-in-code virtual cell program debugging needs a lot of command line for parameter validation, this is a really huge work for debugging such a huge complex system to find out an error. And the system command line just returns 0 or other number from the command line debugging. It’s so much not convenient debugging using the system command line, so I have to develop a script for my program debugging, this idea brings the ShellScript. Now the ShellScript becomes a power tool for my bioinformatics research!

The goal of the ShellScript development is that one simple command and it can do a lot of perfect job for the researchers, because all of the biological researchers are feared of a lot of complexes program code.

Features:

  1. Support LINQ script to query the object-oriented database
  2. Easily developing the API for ShellScript using .NET language Vb.NET/C#/F#
  3. Fully support for the Win32 API
  4. Makes your .NET program scriptable
  5. Support Microsoft .NET Bio
  6. Support LANS.SystemsBiology packages from my “genome-in-code” virtual cell project.
  7. Support Parallel Computing & Query

Some shellscript example to get start this article

Here using a brief example bioinformatics scripting using shellscript for genome map drawing by interaction with circos to start and get your attention:

imports circos
imports assemblyfile.io

ptt <- read.ptt E:\Desktop\xcb_vcell\xc8004\xcb.ptt
circos <- session.create_new

export <- "x:\xc8004_genome_map\"

doc <- circos.generate_doc ptt $ptt myvacog "E:\Desktop\xcb_vcell\xcb_myvacog.csv"
call doc.export doc $doc export_to $export
call shell "perl E:\circos\bin\circos -conf x:\xc8004_genome_map\circos.conf"

Image 1

circos drawing output by interaction with shellscript for bacteria xcc8004 genome

 

Drawing Genetic Clock Diagram

imports diagram.genetic_clock

idlist <- array.new 2.1.1.71-RXN.XC_0035,2PGADEHYDRAT-RXN.XC_2531,2TRANSKETO-RXN.XC_0929,3.4.24.55-RXN.XC_2972,TRNA-NUCLEOTIDYLTRANSFERASE-RXN.XC_0960,1.2.1.32-RXN.XC_0104,1.2.1.67-RXN.XC_0366,1.2.1.9-RXN.XC_0972,1.2.7.8-RXN.XC_0179,1.5.1.15-RXN.XC_1933,1.5.1.20-RXN.XC_0326,1.5.1.20-RXN.XC_3496,1.7.2.2-RXN.XC_2177,1.7.7.2-RXN.XC_2175,1.8.1.4-RXN.XC_2751,1.8.1.4-RXN.XC_3689,1.8.4.8-RXN.XC_0990,1.8.4.8-RXN.XC_0991,1.8.4.8-RXN.XC_1334,1PFRUCTPHOSN-RXN.XC_1743

data <- read.serials "E:\GCModeller\CompiledAssembly\test\EnzymeActivity.csv"
data <- data.select data $data id $idlist
data <- data.interpolate data $data n 2

image <- diagram.createfrom data $data scale 1
call save.bitmap image $image saveto "x:\genetic clock example.bmp"

Image 2

The genetic clock diagram drawing example for the experiment data from the bacteria xcc8004 genome using shellscript "genome-in-code" systems biology package

Shellscript hello world example 

hw <- 'hello world"
msgbox message $hw title "hi!,i'm the test example!"
call test newform $hw

Image 3

and then how about a simple cowsay tricks

msg <- "Moo.. Hi! I'm a cow, but not a real cow, a text drawing cow!"
call $msg -> cowsay

Image 4

hahaha, that's a lot of fun fun.

Acknowledgement

The ShellScript is original developed from the command line interpreter source code which was comes from the Microsoft Windows7 new feature training resource for VisualBasic.

The shellscript was works on a commandline interpreter, the commandline interpreter is define in the namespace Microsoft.VisualBasic.CommandLine which was originally comes from the Microsoft Windows7 Training Resource and I makes the further develop on this commandline interpreter, now it has a lot of advance feature than the Micrsoft developer does.

** The bioinformatics shellscript api libraries (my genome-in-code project library for systems biology researchers) which i make the example in this article is not avaliable for release due to the reason of the scientific paper is not publish yet and it still needs a lot of laboratory experiment validation. and I still hard working on laboratory experiment validate these packages.

 

Using the code

Introductions to the Commandline interpreter

All of the new commandline interpreter feature are relaying on the custom attributes in the namespace Microsoft.VisualBasic.CommandLine.Reflection

VB.NET
''' <summary>
''' Use for the detail description for a specific commandline switch.(用于对某一个命令的开关参数的具体描述帮助信息)
''' </summary>
''' <remarks></remarks>
<AttributeUsage(AttributeTargets.Method, allowmultiple:=True, inherited:=True)>
Public Class SwitchDescription : Inherits Attribute
  
''' <summary>
''' A command object that with a specific name.
''' (一个具有特定名称命令执行对象)
''' </summary>
''' <remarks></remarks>
<AttributeUsage(AttributeTargets.Method, allowmultiple:=False, inherited:=True)>
Public Class CommandAttribute : Inherits Attribute

you can implement the commandline interpreter easily by follows two steps:

  1. Define a commandline delegate handle

You just need to apply a command attribute and then fill the description property, balabala, except the name is required, other property is optional, this keeps your work easy.

If you want your help information on your program commandline more helpful, then you should apply the switchdescription custom attribute on your function, and also the switchdescription attribute is optionally.

Here is a detail implement example for the commandline interpreter.

VB.NET
''' <summary>
''' Using the regular expression to search the motif pattern on a target nucleotide sequence.(使用正则表达式搜索目标序列)
''' </summary>
''' <param name="argvs"></param>
''' <returns></returns>
''' <remarks></remarks>
<Command("-pattern_search", info:="Parsing the sequence segment from the sequence source using regular expression.",
 usage:="-pattern_search -i <file_name> -p <regex_pattern>[ -o <output_directory> -f <format:fsa/gbk>]",
 example:="-pattern_search -i ~/xcc8004.txt -p TTA{3}N{1,2} -f fsa")>
<SwitchDescription(name:="-i", optional:=False,
 description:="The sequence input data source file, it can be a fasta or genbank file.",
 example:="~/Desktop/xcc8004.txt")>
<SwitchDescription(name:="-p", optional:=False,
 description:="This switch specific the regular expression pattern for search the sequence segment,\n" &
              "for more detail information about the regular expression please read the user manual.",
 example:="N{1,5}TA")>
<SwitchDescription(name:="-o", optional:=True,
 description:="Optional, this switch value specific the output directory for the result data, default is user Desktop folder.",
 example:="~/Documents/")>
<SwitchDescription(name:="-f", optional:=True,
 description:="Optional, specific the input file format for the sequence reader, default value is FASTA sequence file.\n" &
              " fsa - The input sequence data file is a FASTA format file;\n" &
              " gbk - The input sequence data file is a NCBI genbank flat file.",
 example:="fsa")>
Public Shared Function PatternSearchA(argvs As Microsoft.VisualBasic.CommandLine.CommandLine) As Integer
   Dim Format As String = argvs("-f")
   Dim Input As String = argvs("-i")
   Dim OutputFolder As String = argvs("-o")
   Dim FASTA As LANS.SystemsBiology.Assembly.SequenceModel.FASTA.File
   Dim pattern As String = argvs("-p").Replace("N", "[ATGCU]")

As you can see, now get the switch parameter from the user input commandline is just easy, if user have specific a value to a specific switch, then you can using CommandLine default property to read the value, if user haven’t specific the value, then default property just return a empty string, don’t worry about this, the commandline interpreter will not get crash.

  1. Declared a commandline interpreter on your program sub Main

After does that, then you can initialize a commandline interpreter on your program sub main:

VB.NET
Module Program

   Public Function Main() As Integer
       Dim strCommandLine As String = Command()

       If Not String.IsNullOrEmpty(strCommandLine) Then
           Dim CommandLine = Microsoft.VisualBasic.CommandLine.CommandLine.TryParse(strCommandLine)
           Return New CommandLine.Interpreter(GetType(CommandLines)).Execute(CommandLine)
       Else
           Call Program.ScriptShell()
       End If

       Return 0
   End Function
End Module

Looks like we make our console program architecture clear: if user have specific a commandline to start our program,  then the commandline interpreter will handle this commandline, if not then our program can do other things.

Manual document auto generated:

CommandLine syntax:

<Program> man

After you have implement the commandline interpreter in you program then you can using the man command in the commandline to display the manual information for your program, and this manual page is automatically generated from your command line attributes.

Help system

Commandline Syntax:

<Program> ? [CommandName]

You can using ? command for get the help information about a sub command that you have define in your commandline interpreter:

If you just specific a? character then the commandline interpreter will list all of the available command that you have define in the commandline interpreter

If you specific a commandName string after the help “?” character with a space, then you can get a more detail help information about the target command.

How it works

Unlike the compiled script does(Script text -> object model -> dynamics assembly): the ShellScript is running in the same way as most Interpreted script language does(script text -> data model -> assign delegate handlers):

Image 5

  • Parsing the script file into command tokens
  • Add the function pointer handler to the command token
  • Execute the API through function pointer handles
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Those two pictures show the differences between the compiled script and interpreted script, details of the work mechanism of the compiled script, you can review one of my previous article: 

[^] http://www.codeproject.com/Articles/721827/LINQ-Script-A-Universal-Object-Oriented-Database-Q

Using the Code

For Developers: how to create the API for ShellScript from VB.NET/C#

Two of the custom attribute will be used in this ShellScript API declaration (Namespace and Command attribute class from the Namespace Microsoft.VisualBasic.CommandLine.Reflection):

VB.NET
''' <summary>
''' (CommandLine interpreter executation Entry and the ShellScript software packages namespace.)这是一个命令行解释器所使用的执行入口点的集合
''' </summary>
''' <remarks></remarks>
<AttributeUsage(AttributeTargets.Class, allowmultiple:=False, inherited:=True)>
Public Class [Namespace] : Inherits Attribute
    Dim _Namespace As String

    Public ReadOnly Property [Namespace] As String
       Get
          Return _Namespace
       End Get
    End Property

    Sub New([Namespace] As String)
       _Namespace = [Namespace]
    End Sub

    Private Shared ReadOnly _TypeInfo As System.Type = GetType([Namespace])
    Public Shared ReadOnly Property TypeInfo As System.Type
       Get
           Return _TypeInfo
       End Get
    End Property

    Public Overrides Function ToString() As String
       Return String.Format("Namespace {0}", _Namespace)
    End Function

    ''' <summary>
    ''' 从目标类型之中构造出一个命令行解释器
    ''' </summary>
    ''' <param name="Type"></param>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public Shared Function CreateInstance(Type As System.Type) As Microsoft.VisualBasic.CommandLine.Interpreter
       Return New Microsoft.VisualBasic.CommandLine.Interpreter(Type)
    End Function
End Class

''' <summary>
''' A command object that with a specific name.
''' (一个具有特定名称命令执行对象)
''' </summary>
''' <remarks></remarks>
<AttributeUsage(AttributeTargets.Method, allowmultiple:=False, inherited:=True)>
Public Class CommandAttribute : Inherits Attribute

   Dim _Name As String

   ''' <summary>
   ''' 这个命令的名称
   ''' </summary>
   ''' <value></value>
   ''' <returns></returns>
   ''' <remarks></remarks>
   Public ReadOnly Property Name As String
      Get
          Return _Name
      End Get
   End Property


   ''' <summary>
   ''' Something detail of help information.(详细的帮助信息)
   ''' </summary>
   ''' <value></value>
   ''' <returns></returns>
   ''' <remarks></remarks>
   Public Property Info As String

   ''' <summary>
   ''' The usage of this command.(这个命令的用法,本属性仅仅是一个助记符,当用户没有编写任何的使用方法信息的时候才会使用本属性的值)
   ''' </summary>
   ''' <value></value>
   ''' <returns></returns>
   ''' <remarks></remarks>
   Public Property Usage As String

   ''' <summary>
   ''' A example that to using this command.(对这个命令的使用示例,本属性仅仅是一个助记符,当用户没有编写任何示例信息的时候才会使用本属性的值)
   ''' </summary>
   ''' <value></value>
   ''' <returns></returns>
   ''' <remarks></remarks>
   Public Property Example As String

   Sub New(Name As String)
      _Name = Name
   End Sub

   Public Overrides Function ToString() As String
      Return Name
   End Function

   Private Shared ReadOnly _TypeInfo = GetType(CommandAttribute)
   Public Shared ReadOnly Property TypeInfo As System.Type
      Get
          Return _TypeInfo
      End Get
   End Property
End Class
  • Namespace declaration

Namesapce means a collection of useful commands, the namespace attribute just allowed applied on a class type declaration, the example like:

VB.NET
<[Namespace]("gcmodeller.engine_kernel.experiment_system")>
Public Class ShellScriptAPI
  • Command declaration

Command is a method for implements a specific function, it should be applied on a shared function in the class which was applied a namespace custom attribute; here is a simple example for creating the ShellScript API using VisualBasic language:

VB.NET
<[Namespace]("gcmodeller.engine_kernel.experiment_system")>
Public Class ShellScriptAPI

    Friend Shared EngineKernel As EngineSystem.Engine.Modeller

    <Command("get.current_time")>
    Public Shared Function Get_currentTime() As Integer
        Return EngineKernel.get_RTime
    End Function

    <Command("build.dynamic.metabolism")>
    Public Shared Function DrawMetabolism() As Microsoft.VisualBasic.ComponentModel.Collection.Generic.KeyValuePairObject(Of Component(), ComponentInteraction())
        Return New DataVisualization.DynamicMap.DynamicMapBuilder(EngineKernel.KernelModule).ExportMetabolismNetwork
    End Function

    <Command("write.network")>
    Public Shared Function SaveNetwork(network As Microsoft.VisualBasic.ComponentModel.Collection.Generic.KeyValuePairObject(Of Component(), ComponentInteraction()), saveto As String) As Boolean
        Dim NetworkCsv As String = String.Format("{0}/Network.csv", saveto)
        Dim NodesCsv As String = String.Format("{0}/ComponentNodes.csv", saveto)

        Call network.Value.SaveTo(NetworkCsv, True)
        Call network.Key.SaveTo(NodesCsv, False)

        Return True
    End Function

    <Command("get.current_time.equals")>
    Public Shared Function CurrentTimeIs(value As Integer) As Boolean
        Return value = EngineKernel.get_RTime
    End Function
End Class

After compile the code of your API then you can use the API that you have created in the ShellScript system. Now using the “?” help command in the ShellScript console you will see the declaration result (type input “? gcmodeller.engine_kernel.experiment_system” from the system console):

Image 6

I’m not recommend the shell script user trying to using this script language to build up a large and complexes program to accomplished the modelling job, as this shell script language is not object oriental. But in contrast I recommend that the developer can develop the shell script module package in VisualBasic.NET and C# language class library and export your API in a well format document and clear interface to this shell script language. And then user can using this shell script to build up a simple and smart tool to finish the research job.

Points on the API creation

  1. using namespace and comand attribute specific the class type and the shared method for export the api to shellscript
  2. register your compiled .NET assembly file using shellscript -register_modules commandline, you can find the detail commandline using ? help command
  3. scripting with your api using shellscript

Integrated the ShellScript with your .NET program and makes the program scriptable

How to Embed the ShellScript into your .NET program, this is just easy, one simple declaration statement:

VB.NET
Dim _EmbeddedScriptEngine As Microsoft.VisualBasic.ShellScript.ShellScript = New ShellScript.ShellScript

And then you can execute the script in your program just one simple command

VB.NET
Call _EmbeddedScriptEngine.EXEC(ScriptText)

here is the EXEC function definition:  

VB.NET
''' <summary>
''' Execute a shellscript file
''' </summary>
''' <param name="ShellScript">
''' This script data should be a line of the script code that of which is user type input from the console terminal
''' or a text file content from the return value of <see cref="FileIO.FileSystem.ReadAllText"></see>
''' </param>
''' <returns></returns>
''' <remarks></remarks>
Public Function EXEC(ShellScript As String) As Integer
    If String.IsNullOrEmpty(ShellScript.Replace(vbCrLf, "").Trim) Then
         Return -1
    Else
#If Not Debug Then
     Try
#End If
         Dim ObjectModel = _Interpreter.CreateObject(ShellScript)
         Call ObjectModel.Execute(HostMemory:=Me._HostMemory)

#If Not Debug Then
     Catch ex As Exception
         Dim OriginalColor = Console.ForegroundColor

         Console.ForegroundColor = ConsoleColor.Red
         Console.WriteLine(vbCrLf & ex.ToString & vbCrLf)
         Console.ForegroundColor = OriginalColor

         Return -1
     End Try
#End If
     Return 0
   End If
End Function

As you can see, the EXEC function have two return value, 0 for ShellScript execute with no error and -1 for exception occurred while execute the ShellScript.

Calling the win32 API

The ShellScript can also using for system management as the feature of it is fully support for the win32 API. Here is a win32 API development example in the ShellScript plugin:

VB.NET
Imports Microsoft.VisualBasic.CommandLine.Reflection

<[Namespace]("winmm.dll")>Public Class WinMM

    <ImportsConstant> Public Const SND_APPLICATION = &H80 ' look for application specific association
    <ImportsConstant> Public Const SND_ALIAS = &H10000 ' name is a WIN.INI [sounds] entry
    <ImportsConstant> Public Const SND_ALIAS_ID = &H110000 ' name is a WIN.INI [sounds] entry identifier
    <ImportsConstant> Public Const SND_ASYNC = &H1 ' play asynchronously
    <ImportsConstant> Public Const SND_FILENAME = &H20000 ' name is a file name
    <ImportsConstant> Public Const SND_LOOP = &H8 ' loop the sound until next sndPlaySound
    <ImportsConstant> Public Const SND_MEMORY = &H4 ' lpszSoundName points to a memory file
    <ImportsConstant> Public Const SND_NODEFAULT = &H2 ' silence not default, if sound not found
    <ImportsConstant> Public Const SND_NOSTOP = &H10 ' don't stop any currently playing sound
    <ImportsConstant> Public Const SND_NOWAIT = &H2000 ' don't wait if the driver is busy
    <ImportsConstant> Public Const SND_PURGE = &H40 ' purge non-static events for task
    <ImportsConstant> Public Const SND_RESOURCE = &H40004 ' name is a resource name or atom
    <ImportsConstant> Public Const SND_SYNC = &H0 ' play synchronously (default)

    <Command("playsoundA")>
    Public Declare Function PlaySound Lib "winmm.dll" Alias "PlaySoundA" (lpszName As String, hModule As Integer, dwFlags As Integer) As Integer
End Class

After compile this class into a DLL files and register in the shell script registry, then you can calling this win32 API in your script file likes this:

MSIL
library ./win32api.dll
imports winmm.dll

filename <- "E:\舞随光动.dat"
call winmm.dll playsounda lpszname $filename hmodule 0 dwflags &snd_filename

Right? This is a multiple media API for playing a wav file. And the plugin class WinMM just an intermediary interface between the C/C++ standard dynamic library and the ShellScript file!

ShellScript syntax

What basically consist of a command statement in shellscript?

CommandType

Syntax

Examples

Value Assignments

<variableName> <- <commandLine>

A <- b

Invoke method

[Call] <CommandLine>

Call command

CommandLine = [Namespace] <commandName> [switch_values]

These example shows you how to write a correct commandline

[call] winmm.dll playsounda lpszname $filename hmodule 0 dwflags &snd_filename

The syntax token call is a prefix of a command line, it indicated that this command will not assign any value to a variable, just like the call keyword in the VisualBasic language, it can be omitted, every VisualBasic programmer knows this syntax attribute.

Then the second token is winmm.dll this is a namespace indicator, it indicated that the next syntax token playsounda will comes from a assembly module which its name is winmm.dll, and all of the character can be using in this syntax tokens as a identifier, but except the space character and system preserved character $(indicated that the identifier is a variable in the memory) and &(indicated that the identifier is a constant in the memory)(but actually you can using the $ and & character in the identifier, but it should not appears in the first character in the identifier).

And then the last syntax tokens lpszname $filename hmodule 0 dwflags &snd_filename is the parameters of the command playsounda and they can be convert into a key value pair:

KeyName(ParameterName)

Value(ParameterValue)

Description

lpszname

$filename

This is a variable reference in the shell script memory

hmodule

0

This is a user define constant

dwflags

&snd_filename

This is a constant reference which comes from the imports command.

Identifier rule in shellscript

identifier is a kind of basically element in the shellscript, it consist the variable name, namespace and method command name in the shellscript. and briefly the shellscript identifier can not start with the character $ or &, and then any other character is legally in the identifier, so this is so differently to the any other programming language that we'v known.

Example

How Interpreter think it is

12345%$%#_*()sfsdds

It’s a identifier “12345%$%#_*()sfsdds”

12345% $%#_*()sfsdds

The identifier is 12345% and its command or function parameter is $%#_*()sfsdds(notice that there is a space character in the example between % and $)

$12345%$%#_*()sfsdds

This is a variable in my memory, but I cannot find this object in the list, so that I just throw an object not found exception

&12345%$%#_*()sfsdds

This is a constant variable in my memory, but I cannot find this object in the dictionary, so that I just throw an object not found exception

Note: as the shellscript using the <- for value assign and using the -> for call the function as extension method, so the operator <- and -> is not allowed in the identifier.

Variable assign prefix character

$  is for all of the normal variables, excepts the imports constants from your API library

& is only for the imports constants which is come from the shellscript api library that you've developed

*  is for the function pointer which is the delegate function that we've create in the shellscript

[Important!!!] Parameter passing rule to the api in the shellscript

It is so strange in the parameter passing from the script line to the.NET assembly API for a newer to my shellscript, but is easily learn for that API function parameter passing just following 3 rules:

  • The api function parameter can be a variable reference in the shellscript memory or directly a constant value.
  • Generally due to the commandline interpreter work mechanism which i've mentioned in the previous section, every parameter value needs a switch name for read from the command. so when you passing the parameters to the function, then every parameter name needs for the parameter value. but if the api function just one parameter, then you can directly passing the parameter from shellscript to api function without specific any other parameter name. the shellscript support the optional parameter. here is a example: 
if the function have more than one parameter:
function_name switch_name1 parametervalue1 switch_name2 parametervalue2....

if the function have just one parameter:
function_name parametervalue
  • object type of the parameter value should matched with the shellscript function parameter due to the reason of visualbasic language is a strong type language and the shellscript is develop by VisualBasic.

Control structures in ShellScript

ShellScript have no Syntactically Indents, and the script is consist of some line of command line, and I more prefer call the shell script as an assembly language like script. So how many control structure does it have?

Here is a table that list all of the available structure control element in the ShellScript

Elements

Syntax

Description

Example

 

     

If

If test <booleanValue> call <commandline>

If test the condition is true then will calling the commandline, if the commandline has a return value, then the returned value will assigned to the variable in the left

Data <- if test $condition call “read.txt $file“

Else

Else <Statement/Expression>

The else command is continute with the previous if command, if the if test condition is true then the else command will not execute, otherwise the if command is not execute then the else command will execute

Data <- else “read.txt $another_file”

For.Each

For.each in <array> call <commandline>

This is the for each structure of the shellscript, the commandline is a script file or temp script line for the command source, each source script have a default variable name array name and the value is one of the element value in the target array object

Result <- for.each in $paths call “source ./test.txt”

 

The./test.txt have a default variable named “paths”

Do.While

 

 

 

Return

Return <value>

This command using for a invoked script return a specific value to its caller script

Return $data

So here is briefly example for showing how to use these control structure elements in the ShellScript:

File <- "test.txt"
Another_file <- "test2.txt"

condition <- TRUE

data <- If test $condition call "read.txt $file"
data <- else "read.txt $another_file"
data <- split text $data delimiter #
data <- for.each in $data call "source ./test3.txt"

Syntax for create delegate method in ShellScript

<delegate_name> <- *
{
   <ShellScript command statements>
}

The delegate is the most powerful feature in VisualBasic and C# language, and the ShellScript is also can create the delegate function.

How to declare a delegate function

Declare the delegate name: delegate name declaration should start with a ShellScript identifier and then a value assignment operator in the identifier right side, then in the command site is a character *, which means the following ShellScript command statements is the delegate function declarations

Each delegate declaration body should wrapped by a pair of closed bracket.

Here is an example delegate for my virtual cell drawing the dynamics metabolism network image using Cytoscape in real-time:

F#
imports gcmodeller.engine_kernel.experiment_system

draw.map <- *
{
  network <- build.dynamic.metabolism
  rtime <- get.current_time
  argvs <- array.new $rtime

  file <- string.format expression "x:\metabolism_{0}_loops.csv" argvs $argvs
  call write.network network $network saveto $file
 
  *free network
}

flag <- get.current_time.equals 5
if test $flag call draw.map

Now from the example we could see, the line of the script “draw.map <- *” is a statement for declares the delegate name. And then the following delegate body was wrapped by a paired of closed bracket. This is the image output from the Cytoscape which was call from the ShellScript in my “genome-in-code” virtual cell real-time calculation. The network from the nature micro bacterial is beautiful isn’t it? This delegate in the shellscript is so much helpful for my complex system debugging operation and the data visualization!

Image 7

shellscript output result using the delegate function for drawing realtime cellsystem network image

 

The extension method

The ShellScript just like vb.net and c# support the extension method, the extension method can enable you to extend the object function without modify the class source code; bring much conveniences to your coding. In the VisualBasic every extension method should declare in a module and the method should have an Extension custom attribute. Create the extension method in the visualbasic like this:

VB.NET
<Command("string.format")>
<Extension>
Public Function Format(Expression As String, argvs As Object()) As String
   Return String.Format(Expression, argvs)
End Function

And then call this extsnsion method like this:

Dim b = "456"
Dim a = "fjsdffrr"
Dim array = {a,b}
Dim Msg As String = "{0} is not {1}".format(array)

The ShellScript also have the extension method syntax, but difference with the visualbasic, you don’t need to add an extension attribute to your function, which means you can directly view the method as its first parameter’s extension method.

here is the extension method syntax:

<variableName>/Value -> <method calling>

ShellScript using the operator "->" to calling a object's member method as the R script does.

So just like the shellscript command API define such as

Public Function Format(Expression As String, argvs As Object()) As String

The first parameter of the function is Expression and it is a string type, so that you can call this API in the shellscript in the extsnsion method way:

Msg <- "{0} is not {1}"-> string.format argvs $array

Here is the whole example using the extension method way:

$  b <- 456
$  a <- fjsdffrr
$  array <- "$a,$b" -> array.new
$  memory

    4 VARIABLES

b       --> 456  //System.String
a       --> asfdaasd  //System.String
array   --> System.Object[]  //System.Object[]

$  msg <- "{0} is not {1}"->string.format argvs $array
$  $msg
   = [0]  asfdaasd is not 456

$  call $msg -> msgbox title 12345

ShellScript Program CommandLine

ShellScript program has three commandlines, while you can use “shellscript man” to get a user manual document:

Man command output from the shellscript commandline interpreter

Microsoft VisualBasic ShellScript(*.vbss) Host [vbss脚本执行引擎] [version 2.2.0.1]
Module AssemblyName: ShellScript.exe
Root namespace: Microsoft.VisualBasic.ShellScript

All of the command that available in this program has been list below:

 -register_linq_modules:  register the linq module into the linq script engine type registry
 -register_modules:  Register the shellscript API module assembly DLL or assembly exe file to the shellscript type registry.

Commands
--------------------------------------------------------------------------------

1.  Help for command '-register_linq_modules':
  Information:  register the linq module into the linq script engine type registry
  Usage:        ShellScript -register_linq_modules -path <assemnly_dll_file>
  Example:      ShellScript -register_linq_modules

2.  Help for command '-register_modules':
  Information:  Register the shellscript API module assembly DLL or assembly exe file to the shellscript type registry.
  Usage:        ShellScript -register_modules -path <assemnly_dll_file> [-module_name <string_name>]
  Example:      ShellScript -register_modules

  Switches information:
   ---------------------------------------
    -path
    Description:  the assembly file path of the API module that you are going to register in the shellscript type library
    Example:      -path ""

   [-module_name]
    Description:  The module name for the register type namespace, if the target assembly just have one shellscript namespace, then this switch value will override the namespace attribute value if the value of this switch is not null, when there are more than one shellscript namespace was declared in the module, then this switch opetion will be disabled.
    Example:      -module_name ""

There are some important command you should remembered

  • Library: register an external assembly module in your script

When you are going to use a command in an assembly file, the assembly file should register in the ShellScript registry first, or it will throw an exception about assembly module not found. Using the command line to register the module is good, but this is not makes your script file much convenient for publish to your user. So that you should using this library command before you are about to calling a command in the assembly module, because it can register a assembly module file into the registry dynamics.

Library <DLL/EXE relative path>
Call <commands>
  • Libraries: list all of the available registered assembly module

The libraries command can be enumerate all of the registered assembly module in the ShellScript registry, if you have register any other module in the ShellScript, then you can using this command to see the overviews:

Image 8

  • Imports: Namespace imports command

The system build-in command does not required any namespace prefix when you are about to call these command, but the user command is not, before you imports a namespace, each time you using a external user command you should have a namespace prefix before the command name token, but after you imports the namespace, you can directly Call the command without any namespace prefix, this is the same function as the imports keyword in the VisualBasic language

  • ?: Help command

? is a help command in ShellScript, it have one parameter, the parameter can be a method name or an assembly module namespace

If you are using the command “? <method name>” then shell script will print the detail help information of the specific method command, if the ShellScript can find how to load it into the memory.

If you are using the command “? <module namespace>” then the ShellScript will print all of the shell command that the developer write in the program

Image 9

Help example for gcmodeller.compiler namespace from my genome-in-code project

The help command list all of the available command method in the gcmodeller.compiler namespace, method entry column is the command name that you can call in the script and the return type column is the return system of the target command

This is just the overview of a namespace, and then you can continues using the command “? <namespace> <commandname>” to view the command details information

Image 10

Help example for invoke.compile method for the gcmodeller.compiler namespace

VB.NET
<Command("Invoke.compile", info:="invoke the compiler compile method to compile the data into a virtual cell model file.",
     usage:="invoke.compile compiler $compiler argvs $argv_string",
     example:="call gcmodeller.compiler invoke.compile compiler $compiler argvs $argv_string")>
Public Shared Function Compile(compiler As LANS.SystemsBiology.Assembly.DocumentFormat.CsvTabular.Compiler.Compiler, argvs As String) As DocumentFormat.CsvTabular.FileStream.CellSystem
    Call compiler.Compile(argvs)
    Return compiler.Return
End Function

All of the help information is originally comes from the command custom attribute as you can see in the command definition example.

  • Source: source command for calling another script file and get its return value
syntax
source <script_file_path> [switch1 parametervalue1 switch2 parametervalue2 ...]
  • Q(): Quit the program

Maybe you have notice that the ShellScript syntax is something like the language R, and the R is using q() for exists the script environment, so that the ShellScript is also using the q() for exit the program.

License

This article, along with any associated source code and files, is licensed under The GNU General Public License (GPLv3)


Written By
Technical Lead PANOMIX
China China
He is good and loves VisualBasic! Senior data scientist at PANOMIX


github: https://github.com/xieguigang

Comments and Discussions

 
-- There are no messages in this forum --