Skip to content

CLI Script Execution

Oleg Shilo edited this page Jan 5, 2022 · 18 revisions

In this article:


Overview

Script stand-alone execution is the most mature and stable part of CS-Script feature set. Thus, the major documentation has been written quite some time ago and while it may currently have some referencing discrepancies (e.g. VS2012 instead of VS2015) it is still an accurate primary source of CS-Script knowledge. This Wiki article, on the other hand, is the most concise and concentrated description of the relevant content and in the vast majority of the cases, it will be fully sufficient for the majority of the readers. In all other cases (e.g. older versions of CS-Script) please refer to the legacy Online documentation.

CS-Script allows direct single-step execution of files containing ECMA-compliant C# code. Canonical Hello World script:

using System;
Console.WriteLine("Hello World!");

The script engine executable comes in three forms:

  • cscs.dll - Console application assembly. Available on both Windows and Linux.
  • css - Native executable. It simply launches the script engine assembly (cscs.dll) without the need to invoke .NET launcher:
    css --version
    
    instead of
    dotnet /usr/local/bin/cs-script/cscs.dll --version
    
  • csws.dll - Windows application assembly (available only on Windows). It is a script engine compiled as a Windows application assembly (as opposed to console application). You may want to use it when executing the scripts that run as a Windows application without a console window attached. csws.dll is only available on Windows.

The simplest way to execute the C# script is to run the script engine (css) and pass the script file as a parameter.

css script.cs

Any OS that has CS-Script installed can run C# scripts. The minimal distribution file set is the script file itself. Of course, if the script depends on the third-party library or other scripts then they also need to be deployed on the target system.

Optionally it may convert the script into a self-sufficient single executable with

PS C:\Users\user> css -e test.cs
Created: C:\Users\user\test.exe

Features

From the start, CS-Script was heavily influenced by Python and the developer experiences it delivers. Thus, it tries to match the most useful Python features (apart from the Python syntax). Here are some highlights of the CS-Script features.

  • Scripts are written in plain vanilla CLS-compliant C#. Though classless scripts (top-level statements) are also supported.
  • Remarkable execution speed matching performance of compiled managed applications.
  • Including (referencing) dependency scripts from the main script.
  • Referencing external assemblies from the script.
  • Automatic referencing external assemblies based on analyses of the script-imported namespaces ('usings').
  • Automatic resolving (downloading and referencing) NuGet packages.
  • Building a self-sufficient executable from the script.
  • Possibility to plug in external compiling services for supporting alternative script syntax (e.g. VB, C++)
  • Scripts can be executed on Windows, Linux and MacOS (.NET5 needs to be present).
  • Full integration with Windows, Visual Studio, VSCode, Notepad++ (CS-Script plugin for Notepad++ brings true IntelliSense to the 'peoples editor'), Sublime Text 3

CS-Script directives

CS-Script relies on so-called 'script directives' for implementing some features. These directives are the C# comments that do not obstruct standard C# compilers and yet provide user-defined instructions for the script engine.

Simple WebAPI server top-level statement script:

//css_include webapi;     - include webapi.cs script
//css_include my_dto.cs;  - include DTO definitions script
//css_nuget NLog;         - reference NLog assembly
using System;
using WebApi;

WebApi.SimpleHost
      .StartAsConosle("http://localhost:8080",
      . . .

The complete set of the directives as well as the details about the complete scripting syntax can be found here: https://github.com/oleg-shilo/cs-script/wiki/Script-Syntax

Editing scripts

The scripts can be edited with any suitable text editor. Though if want to take advantage of IntelliSense you may prefer Visual Studio or VSCode with CS-Script extensions.

You can also use Notepad++ or Sublime Text 3 with CS-Script extensions. While these editors do not have debugging tools they are still very capable and will be an adequate choice for most of the cases.

VSCode is arguable is the most versatile editor out of all. It is a true IDE and it is available on all OSs.

CS-Script has two built-in commands for easy loading scripts in Visual Studio and VSCode

Though in many cases you may be better off with just Notepad++. You will need to enable C# IntelliSense plugin from the plugin manager. This plugin was developed specifically to allow VS-like experience when dealing with C# scripts and any C# code. The plugin comes with its own CS-Script package and allows true C# IntelliSense assisted editing.

Installing CS-Script

Installing dependencies

CS-Script requires .NET 5 or higher: https://dotnet.microsoft.com/download/dotnet. CS-Script relies on .NET tools (compilers) when it executes scrips. Meaning that you will need to ensure a complete .NET suite (that includes SDK) is installed.

Interestingly enough you can use CS-Script on a system that only has .NET Runtime installed but no SDK (.NET tools). This is because one of the supported engines, Roslyn, does not require any extra tools. Though it does have some limitations.

Installing CS-Script engine

Installing as a package on Windows

The simplest way to start using CS-Script is to install it from Chocolatey, which is a repository for the Windows software packages. Chocolatey it is a Windows version of Linux apt-get. CS-Script can be installed with the following command:

C:\> choco install cs-script

Installing a package on Linux

If you want to install CS-Script on Linux (e.g. Ubuntu) you can use Debian package included in every release.

You can copy the terminal command for the specific release from the corresponding release page on the Releases. Below is an example of the command for installing CS-Script version 4.1.0.0.

repo=https://github.com/oleg-shilo/cs-script/releases/download/v4.1.0.0/; file=cs-script_4.1-0.deb; rm $file; wget $repo$file; sudo dpkg -i $file

Generic (manual) install

Just unpack the corresponding 7z file from Releases page and start using the script engine executable cscs.

If you prefer you can build a shim exe css for an easy launch of the script engine process:

cscs -self-exe

The same shim/symbolic link is created if you are installing the CS-Script as a package.

Quick Start

Creating and executing sample script

  • css -new sample.cs - creates a sample sample.cs script file.
  • css sample.cs - execute sample.cs script

Note, the content of the sample file may vary depending on the CS-Script version). Thus, in the sample below an older version of the script engine uses -s ("print sample") command to generate the scripts.

Produced sample.cs file:

using System;
using System.Windows.Forms;

class Script
{
    static void Main(string[] args)
    {
        for (int i = 0; i < args.Length; i++)
            Console.WriteLine(args[i]);

        MessageBox.Show("Just a test!");
    }
}

Hints and tips

  • You can print the list of all supported commands with cscs -cmd

  • You can access help for a specific command by typing ? after the command name (e.g. cscs -syntax -?)

  • You can print the whole overview of CS-Script specific C# directives with cscs -syntax

  • The most common/useful CS-Script directives that you can specify directly in the script are:

  • When referencing external files with //css_ directives (e.g. //css_inc) it is important to be aware about the way CS-Script resolves relative paths.

    If a relative file path is specified with a single-dot prefix it will be automatically converted into an absolute path with respect to the location of the file containing the directive being resolved. Otherwise, it will be resolved with respect to the process current directory.

    If for whatever reason it is preferred to always resolve path expression with respect to the parent script location you can configure the script engine to do it with the following command:

    css -config:set:ResolveRelativeFromParentScriptLocation=true
    
  • With the -pc switch you can define a precompiler script that allows pre-processing the primary script content prior its execution. Precompilation allows achieving pretty advanced functionality usually available in some advanced AOP framework. For example code decoration, macros unfolding etc.

  • Instead of passing arguments from the command line, you specify them directly in the script code with //css_args directive.

  • The most frequently used command line arguments can be specified in the global configuration so they will be automatically added during the execution for all scripts (e.g. suppressing warnings).

  • On Windows/.NET you can pass //x as the very last argument of the script and this will trigger a Debug.Assert on entering the script code. This way you can attach system-wide debugger and debug the script:

    css print.cs "Hello World!" //x
    

Command Line Interface

The whole CLI documentation can be generated with the script engine itself by either of the methods below:

  • cscs -? cli command for printing CLI help as text. You can also access its latest online copy of as text content here.
  • cscs -? cli:md command for printing CLI help as markdown. You can also access its latest online copy of as text content here.

You can also access CS-Script specific syntax help topics via cscs -syntax command.

Note, this page does not cover the whole CLI but only highlights its most important elements. Below are only a few commands samples:


Command: "version"

Syntax: css -ver (or just css)

Description: Prints full information about the current CS-Script environment.


Command: "commands"

Syntax: css -cmd

Description: Prints list of supported commands (arguments).

Syntax: css -cmd ?

Description: Prints description of an individual command.


Command: "build executable - EXE"

Syntax: css -e <script_file>

Description: Compiles script into an application executable.

Command: "build class library - DLL"

Syntax: css -cd <script_file>

Description: Compiles script into a class library assembly.


Command: "compiler options"

Syntax: css -co:<options> <script_file>

Description: Passes user-specified options into C# compiler.

The sample below demonstrates how to compile unsafe code. Any unsafe code requires passing /unsafe parameter to the C# compiler:

using System;
using static dbg;

unsafe void main()
{
    int i = 25;
    SquarePtrParam(&i);
    print(i);
}

unsafe void SquarePtrParam(int* p)
{
    *p *= *p;
}


Command: "auto-class"

Syntax: css -ac[:<0|1|2|out>] <script_file>

Description: Decorates classless C# script code with a class definition prior the execution.

NOTE, this is working but an obsolete API and it is recommended that you use .NET native feature "top-level statement" instead:

css -new:toplevel script.cs`.

The content of script.cs script:

using System;
using System.IO;
using System.Diagnostics;
using static dbg; // for print() extension
using static System.Environment;

print("Script: ", GetEnvironmentVariable("EntryScript"));

@".\".list_files();

static class extensions
{
    public static void list_files(this string path)
        => Directory
               .GetFiles(path)
               .print();
}

And when executed:

D:\dev\>css sample.cs
Script:  D:\dev\sample.cs
{string[]} - Length: 15 items
  [0]: ".\-code.header"
  [1]: ".\cscs.deps.json"
  [2]: ".\cscs.dll"
  [3]: ".\cscs.exe"
  [4]: ".\cscs.runtimeconfig.json"
  [5]: ".\css.cs"
  [6]: ".\csws.deps.json"
  [7]: ".\csws.dll"
  [8]: ".\csws.exe"
  [9]: ".\csws.runtimeconfig.json"
  [10]: ".\Microsoft.CodeAnalysis.CSharp.dll"
  [11]: ".\Microsoft.CodeAnalysis.CSharp.Scripting.dll"
  [12]: ".\Microsoft.CodeAnalysis.dll"
  [13]: ".\Microsoft.CodeAnalysis.Scripting.dll"
  [14]: ".\ttt.cs"

Command: "pre-compiler"

Syntax: cscs -pc:<precompiler_file> <script_file>

Description: Specifies custom precompiler. This can be either script or assembly a file. (see https://www.cs-script.net/cs-script/help-legacy/precompilers.html)

-pc           - If no file is specified it prints the code template for the custom precompiler.
-pc:print     - Prints the code template for the custom precompiler.
-pc:nodefault - Prevents loading any built-in precompilers.
                (E.g. The one for removing shebang before the execution. Auto-class precompiler
                - classless script decorator)
-pc:<file 1>[,<file N>]
              - Precompiles the script with the specified precompiler(s).

Script recompilation is a powerful mechanism somewhat similar to the C++ precompilation. It gives user an unrestricted ability to massage (modify) the source code just before it's fed to the compiler. The feature can be extremely valuable for adding language features that are not directly available in C#. Anything from executing encrypted scripts to advanced DSL features.

The following is a script sample that uses heshdef.cs precompiler to support C++ style #define macros for C#:

Note, the sample uses //css_pc directive directly in the script C# code. This directive is a full equivalent of -pc CLI command.

//css_pc hashdef
using System;

#define PRINT Console.WriteLine
#define USER Environment.UserName.GetHashCode()
#define GRITTING $"Hello {USER}!"

class Script
{
    static public void Main()
    {
        PRINT(GRITTING);
    }
}