How to make program accept glob (wildcards) at command line? - c#

I would like users to be able to run my program (from Windows cmd) with syntax like this
app.exe *.pdf
app.exe February/*.pdf March/*.pdf
app.exe contracts.pdf
The app would then do its business for each of the relevant files. In Unix this is called globbing and it's done by the shell.
How can I achieve this for a Windows C# command line app?
Hypothetical syntax
void Main(string[] args)
{
foreach(var file in args.SelectMany(arg => Glob.Expand(arg)))
{
Process(file)
}
}

take a look at NuGet package Microsoft.Extensions.FileSystemGlobbing
https://learn.microsoft.com/en-us/dotnet/api/microsoft.extensions.filesystemglobbing.matcher

The easiest way to do this is to convert the command line parameter into a regular expression. See glob pattern matching in .NET for an example on how to convert the command line argument into a regular expression.

Related

Is there a way to turn several csharp repl commands into a terminal alias?

Every day I make a GUID which I copy to my clipboard.
I do this by opening my terminal, writing csharp (see link below in case you are confused), writing GUID.NewGuid(), copying the output and writing quit.
Is there any way I can turn this whole procedure into a terminal alias?
Edit:
Just to clarify, I'm using this:
https://www.mono-project.com/docs/tools+libraries/tools/repl/
You can write and compile a console application, the question was geared towards whether you can inject statements directly into the command-line tool, not how to make a tiny executable.
There is an easy command from BSD to generate a UUID, it's available in macOS.
uuidgen
If you need to copy the UUID result to clipboard, use this:
uuidgen | pbcopy
So, what's the difference between UUID and GUID? Check out this thread.
Create a C# program
using System;
namespace guid
{
class MainClass
{
public static void Main(string[] args)
{
new MainClass().run();
}
private void run()
{
Console.WriteLine(Guid.NewGuid());
}
}
}
Compile to new-guid
Use in zsh like this
guid=$(./new-guid) #you may have to change the `.` to the appropriate path, depending on where the program is.
echo "${guid}"
Tested with zsh and mono-develop in Debian Gnu/Linux.
Note there are probably better ways to do this. One line purl script, or may be some Unix command.
Here's the answer I was looking for, in this case:
csharp -e 'Guid.NewGuid();' | pbcopy

Run C# code on linux terminal

How can I execute a C# code on a linux terminal as a shell script.
I have this sample code:
public string Check(string _IPaddress,string _Port, int _SmsID)
{
ClassGlobal._client = new TcpClient(_IPaddress, Convert.ToInt32(_Port));
ClassGlobal.SMSID = _SmsID;
string _result = SendToCAS(_IPaddress, _Port, _SmsID );
if (_result != "") return (_result);
string _acoknoledgement = GetFromCAS();
return _acoknoledgement;
}
When I run a shell bash I use #!/bin/bash. There is how to do the same with C#?
Of course it can be done and the process is extremely simple.
Here I am explaining the steps for Ubuntu Linux.
Open terminal:
Ctrl + Alt + T
Type
gedit hello.cs
In the gedit window that opens paste the following example code:
using System;
class HelloWorld {
static void Main() {
Console.WriteLine("Hello World!");
}
}
Save and close gedit.
Back in terminal type:
sudo apt update
sudo apt install mono-complete
mcs -out:hello.exe hello.cs
mono hello.exe
Output:
Hello World!
NOTE: #adabru's answer below makes my solution obsolete unless you are using an older mono platform.
C# scripts can be run from the bash command line just like Python and Perl scripts, but it takes a small bit of bash magic to make it work. As Corey mentioned above, you must first install Mono on your machine. Then, save the following code in an executable bash script on your Linux machine:
if [ ! -f "$1" ]; then
dmcs_args=$1
shift
else
dmcs_args=""
fi
script=$1
shift
input_cs="$(mktemp)"
output_exe="$(mktemp)"
tail -n +2 $script > $input_cs
dmcs $dmcs_args $input_cs -out:${output_exe} && mono $output_exe $#
rm -f $input_cs $output_exe
Assuming you saved the above script as /usr/bin/csexec, an example C# "script" follows:
#!/usr/bin/csexec -r:System.Windows.Forms.dll -r:System.Drawing.dll
using System;
using System.Drawing;
using System.Windows.Forms;
public class Program
{
public static void Main(string[] args)
{
Console.WriteLine("Hello Console");
Console.WriteLine("Arguments: " + string.Join(", ", args));
MessageBox.Show("Hello GUI");
}
}
Save the above code to a file such as "hello.cs", make it executable, change the first line to point to the previously saved bash script, and then execute it, you should see the following output along with a dialog saying "Hello GUI":
bash-4.2$ ./hello.cs foo bar baz
Hello Console
Arguments: foo, bar, baz
Note that the GUI requires that you be at run level 5. Here is a simpler C# script that runs at a pure text console:
#!/usr/bin/csexec
using System;
public class Program
{
public static void Main(string[] args)
{
Console.WriteLine("Hello Console");
Console.WriteLine("Arguments: " + string.Join(", ", args));
}
}
Notice that the command line arguments are passed to the C# script, but the shebang arguments (in the first C# script above "-r:System.Windows.Forms.dll -r:System.Drawing.dll") are passed to the C# compiler. Using the latter functionality, you can specify any compiler arguments you require on the first line of your C# script.
If you are interested in the details of how the bash script works, shebang (#!) lumps together all arguments passed to it on the first line of the C# script, followed by the script name, followed by command line arguments passed to the script itself. In the first C# example above, the following 5 arguments would be passed into the bash script (delineated by quotes):
"-r:System.Windows.Forms.dll -r:System.Drawing.dll" "hello.cs" "foo" "bar" "baz"
The script determines that the first argument is not a filename and assumes it contains arguments for the C# compiler. It then strips off the first line of the C# script using 'tail' and saves the result to a temporary file (since the C# compiler does not read from stdin). Finally, the output of the compiler is saved to another temporary file and executed in mono with the original arguments passed to the script. The 'shift' operator is used to eliminate the compiler arguments and the script name, leaving behind only the script arguments.
Compilation errors will be dumped to the command line when the C# script is executed.
The #! (hashbang) tag is used to tell the shell which interpreter to use so that your perl, php, bash, sh, etc. scripts will run right.
But C# is not a scripting language, it is intended to be compiled into an executable format. You need to install at least a compiler and runtime if you want to use C#, and preferably an IDE (Integrated Development Environment) to help you develop and debug your applications.
Install Mono for the compiler and runtime, then MonoDevelop for the IDE.
After installing mono you can use csharp hello.cs. Starting with Mono 2.10, you can also use the shebang like this:
#!/usr/bin/csharp
Console.WriteLine ("Hello, World");
If you need assemblies, you can load them e.g. with the line LoadAssembly("System.IO.Compression") inside your script.
Reference: man csharp.
You can't execute C# like a script, you have to compile it first. For that, you could install mono.
You can then compile your program with mcs and execute it with mono.
First, you have to install mono
sudo apt install mono-complete
Commands to execute
mcs -out:$1.exe $1.cs
mono $1.exe
You can add these in a script to make the process easier. Create a shell sript and add the parent directory to the PATH environment variable.
Example:
export PATH=$PATH":$HOME/Desktop/customcommands"
And also give execute permission to the script file.
Shell script:
#!/bin/sh
dpkg -s mono-complete > /dev/null
if [ $? -eq 0 ]; then
echo
else
read -p "Package mono-complete not installed. Press y to install or n to quit." response
yes="y"
if [ "$response" = "y" ];
then
sudo apt install mono-complete
echo " "
echo " "
fi
fi
mcs -out:$1.exe $1.cs
mono $1.exe

Current directory from a DLL invoked from Powershell wrong

I have a DLL with a static method which would like to know the current directory. I load the library
c:\temp> add-type -path "..."
...and call the method
c:\temp> [MyNamespace.MyClass]::MyMethod()
but both Directory.GetCurrentDirectory() and .Environment.CurrentDirectory get the current directory wrong...
what is the correct way to do this?
There are two possible "directories" you can have in powershell. One is the current directory of the process, available via Environment.CurrentDirectory or Directory.GetCurrentDirectory(). The other "directory" is the current location in the current Powershell Provider. This is what you see at the command line and is available via the get-location cmdlet. When you use set-location (alias cd) you are changing this internal path, not the process's current directory.
If you want some .NET library that uses the process's current directory to get the current location then you need to set it explicitly:
[Environment]::CurrentDirectory = get-location
Powershell has an extensible model allowing varying data sources to be mounted like drives in a file system. The File System is just one of many providers. You can see the other providers via get-psprovider. For example, the Registry provider allows the Windows Registry to be navigated like a file system. Another "Function" lets you see all functions via dir function:.
If the command in your DLL inherits from System.Management.Automation.PSCmdLet, the current PS location is available in SessionState.Path.
public class SomeCommand : PSCmdlet
{
protected override void BeginProcessing()
{
string currentDir = this.SessionState.Path.CurrentLocation.Path;
}
}
To get to the path without a session reference, this code seems to work. This solution I found after going through code that makes GIT autocomplete in PS GIT Completions, specifically this function here.
public class Test
{
public static IEnumerable<string> GetPath()
{
using (var ps = PowerShell.Create(RunspaceMode.CurrentRunspace))
{
ps.AddScript("pwd");
var path = ps.Invoke<PathInfo>();
return path.Select(p => p.Path);
}
}
}
Output:
PS C:\some\folder> [Test]::GetPath()
C:\some\folder

Is there a way to make msbuild write error output to stderr?

It appears msbuild writes all output (including error output) to standard output.
Is there some way to have it write error output (what's normally output in red) to standard error instead?
I'm writing a .NET application with a WPF and console interface and calling msbuild using System.Diagnostics.Process. I'd like to be able to distinguish error output to the user somehow.
Is there a better of separating the output than looking for "error " in each line or using Microsoft.Build directly + a custom logger?
Take a look at the MSBUILD.EXE command line arguments page. Specifically the consoleloggerparameters switch.
You can use /clp:ErrorsOnly to display only errors in the console output.
If you need the rest of the output, include an errors only file log with
/fl4 /flp4:errorsOnly;logfile=MSBuild.Errors.log
then monitor the file for new lines.
I know you said you wanted to avoid a custom logger, but... I also wanted error output on stderr and found that writing a custom logger was not that painful - 1 class with 1 method with 1 statement:
using Microsoft.Build.Utilities;
using Microsoft.Build.Framework;
public class ErrorOnlyLogger : Logger
{
public override void Initialize(IEventSource eventSource)
{
eventSource.ErrorRaised += (s, e) => {
System.Console.Error.WriteLine(
"{0}({1},{2}): error {3}: {4} [{5}]",
e.File, e.LineNumber, e.ColumnNumber, e.Code, e.Message, e.ProjectFile);
};
}
}
This uses the same error formatting as msbuild. This works with command-line msbuild 14.0.25420.1. The code references Microsoft.Build.Utilities.Core.dll and Microsoft.Build.Framework.dll in C:\Program Files (x86)\MSBuild\14.0\Bin. I add /logger:ErrorOnlyLogger,path\ErrLogger.dll to the command line to invoke it.

Why do 'requires' statements fail when loading (iron)ruby script via a C# program?

IronRuby and VS2010 noob question:
I'm trying to do a spike to test the feasibility of interop between a C# project and an existing RubyGem rather than re-invent that particular wheel in .net. I've downloaded and installed IronRuby and the RubyGems package, as well as the gem I'd ultimately like to use.
Running .rb files or working in the iirb Ruby console is without problems. I can load the both the RubyGems package, and the gem itself and use it, so, at least for that use case, my environment is set up correctly.
However, when I try to do the same sort of thing from within a C# (4.0) console app, it complains about the very first line:
require 'RubyGems'
With the error:
no such file to load -- rubygems
My Console app looks like this:
using System;
using IronRuby;
namespace RubyInteropSpike
{
class Program
{
static void Main(string[] args)
{
var runtime = Ruby.CreateRuntime();
var scope = runtime.ExecuteFile("test.rb");
Console.ReadKey();
}
}
}
Removing the dependencies and just doing some basic self-contained Ruby stuff works fine, but including any kind of 'requires' statement seems to cause it to fail.
I'm hoping that I just need to pass some additional information (paths, etc) to the ruby runtime when I create it, and really hoping that this isn't some kind of limitation, because that would make me sad.
Short answer: Yes, this will work how you want it to.You need to use the engine's SetSearchPaths method to do what you wish.
A more complete example
(Assumes you loaded your IronRuby to C:\IronRubyRC2 as the root install dir)
var engine = IronRuby.Ruby.CreateEngine();
engine.SetSearchPaths(new[] {
#"C:\IronRubyRC2\Lib\ironruby",
#"C:\IronRubyRC2\Lib\ruby\1.8",
#"C:\IronRubyRC2\Lib\ruby\site_ruby\1.8"
});
engine.Execute("require 'rubygems'"); // without SetSearchPaths, you get a LoadError
/*
engine.Execute("require 'restclient'"); // install through igem, then check with igem list
engine.Execute("puts RestClient.get('http://localhost/').body");
*/
Console.ReadKey();

Categories