Click here to Skip to main content
Click here to Skip to main content

LINQ on the Command-Line

, 4 May 2012
Rate this:
Please Sign up or sign in to vote.
Ever want to run a Linq statement from powershell or command line?

Introduction

Have you ever wanted to run a .linq script on the power shell or command line and go all functional? Linqoott is a console LINQ execution engine.  It reads .linq files and dumps the output to the console. 

Using the Code   

First we get the script source from the first argument: 

var isLinq = args[0].ToLower().EndsWith(".linq");

Find out the LINQ "kind"... (statement/expression)  

string linqType = (isLinq)?XDocument.Parse(lins[0]).Root.Attribute("Kind").Value:string.Empty;

Is it a single expression or a statement (multiple lines), this effects how you format the script into a code block.

var script = string.Format(("Statements" == linqType) ? "{0}\nreturn null;" : "return {0};",
    string.Join("\n", (isLinq) ? lins.Skip(2).Where(s => !s.TrimStart().StartsWith("//")) : lins));

Have a script, must execute.  Not as hard as you think, embed the script in a template C# Main().  It looks like this: 

static readonly string[] tmplApp = new string[]{
"using System;",
"using System.Collections.Generic;",
"using System.Linq;",
"using System.Xml.Linq;",
"using System.Text;",
"using System.IO;",
"",
"class Script{ public static object Main(string[] args){{CODE}} }",
"",
"public static class ScriptExtensions",
"{",
"    public static object Dump(this object value)",
"    {",
"        if (null != value)",
"        {",
"            if (value is IEnumerable<object>)",
"                Console.WriteLine(string.Join(\"\\n\", (value as IEnumerable<object>).Select(s => s.Dump().ToString())));",
"            else",
"                Console.WriteLine(value);",
"        }",
"        return value;",
"    }",
"    public static object ToFile(this object value, string fileName) { File.WriteAllText(fileName, value.Dump()); return value; }", 
"}"};

The "Dump" method embedded in there is to help output the values in statements. 

Next we "compiled" the source.  I can't claim credit here see the Code Project Article: Dynamic Code Integration

private static Assembly CompileSource(string sourceCode)
{
    CodeDomProvider cpd = new CSharpCodeProvider();
    CompilerParameters cp = new CompilerParameters() { GenerateExecutable = false };
    cp.ReferencedAssemblies.AddRange(new string[] { "System.dll", "System.Xml.dll", "System.Xml.Linq.dll", "System.Core.dll", "System.Data.dll" });
 
    // Invoke compilation.
    CompilerResults cr = cpd.CompileAssemblyFromSource(cp, sourceCode);
 
    return cr.CompiledAssembly;
}

So we have this vague "Assembly" object thingy... What do we do with it? This is a good time to reflect. NO! not on your coding skills, System.Reflection, you hack monkey!

var scrObj = asm.CreateInstance("Script");
try{
  object result = scrObj.GetType().InvokeMember("Main", BindingFlags.InvokeMethod, null,scrObj,     	new object[] { args.Skip(1).ToArray() });
  if ("Statements" != linqType)
        result.Dump();
}
catch (Exception x)
{
    Console.WriteLine("Failed executing script:\n\n{0}\n\n{1}", script, x.Message); 
}

And that's it! You can run a script...

Samples Worth a Thousand Bugs

Here's a LINQ script sample. This enumerates your 'C:\program files' directory and returns all .exe's with a file major version greater than 10, and sorts by minor version. Silly example, but it exercises the code.

Directory.GetFiles(@"c:\program files", "*.exe", SearchOption.AllDirectories)
 .Where(v=>v.FileMajorPart>10).OrderBy(v=>v.FileMinorPart)
 .Select(f=>f.FileName.Replace(@"c:\program files", args[0]))
 .ToArray().Select(f=>FileVersionInfo.GetVersionInfo(f))

Let's execute that ... On my machine it returns:

c:\foo\Common Files\logishrd\WUApp64.exe
c:\foo\Common Files\Microsoft Shared\DW\DW20.EXE 
c:\foo\Common Files\Microsoft Shared\DW\DWTRIG20.EXE
c:\foo\Common Files\Microsoft Shared\OFFICE14\MSOICONS.EXE
c:\foo\Common Files\Microsoft Shared\OFFICE14\MSOXMLED.EXE 
... 

Wait a minute?!  "c:\foo\..." where did that come from? Hmm, I added arguments. See this:

 .Select(f=>f.FileName.Replace(@"c:\program files", args[0]))

That replaces "c:\program files" with the first passed command-line argument,  in this case "c:\foo" (see sample project's debug settings). Pretty cool Wink | ;)   

As always, code safe!   

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

About the Author

CodingBruce
Engineer Big Company
United States United States
My professional career began as a developer fixing bugs on Microsoft Word97 and I've been fixing bad habits ever since. Now I do R&D work writing v1 line of business applications mostly in C#/.Net.
 
I've been an avid pilot/instructor for 13+ years, I've built two airplanes and mostly fly gliders now for fun. I commute in an all-electric 1986 BMW 325 conversion.
 
I'd like to get back to my academic roots of programming 3D analysis applications to organize complex systems.

Comments and Discussions

 
SuggestionLINQPad Command Line PinmemberAndrew Rissing12-Oct-12 5:21 
GeneralRe: LINQPad Command Line PinmemberCodingBruce11-Dec-12 17:12 
That was actually the inspiration for this
-bruce

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Mobile
Web02 | 2.8.140721.1 | Last Updated 4 May 2012
Article Copyright 2012 by CodingBruce
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid