With .NET Core now being a cross-platform framework, it’s very easy to invoke a Bash script from C# codes. It’s not a common practice, but in cases that are lack of a .NET library or REST/rpc API, being able to run a script out-of-process is valuable. So here is a nice extension method that I wrote and found it a joy to call.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
public static class ShellHelper | |
{ | |
public static Task<int> Bash(this string cmd, ILogger logger) | |
{ | |
var source = new TaskCompletionSource<int>(); | |
var escapedArgs = cmd.Replace("\"", "\\\""); | |
var process = new Process | |
{ | |
StartInfo = new ProcessStartInfo | |
{ | |
FileName = "bash", | |
Arguments = $"-c \"{escapedArgs}\"", | |
RedirectStandardOutput = true, | |
RedirectStandardError = true, | |
UseShellExecute = false, | |
CreateNoWindow = true | |
}, | |
EnableRaisingEvents = true | |
}; | |
process.Exited += (sender, args) => | |
{ | |
logger.LogWarning(process.StandardError.ReadToEnd()); | |
logger.LogInformation(process.StandardOutput.ReadToEnd()); | |
if (process.ExitCode == 0) | |
{ | |
source.SetResult(0); | |
} | |
else | |
{ | |
source.SetException(new Exception($"Command `{cmd}` failed with exit code `{process.ExitCode}`")); | |
} | |
process.Dispose(); | |
}; | |
try | |
{ | |
process.Start(); | |
} | |
catch (Exception e) | |
{ | |
logger.LogError(e, "Command {} failed", cmd); | |
source.SetException(e); | |
} | |
return source.Task; | |
} | |
} |
To call the method, one can simply do, e.g.:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
await $"scripts/00magic.sh --param {arg}".Bash(this.logger); |