Po dłuższej przerwie od blogowania zacznę na rozgrzewkę od przyjemnego i krótkiego tematu. Pokaże jak uruchomić polecenie powłoki systemowej bash w .NET Core na Ubuntu. Na podstawie przedstawionej metody będzie można w analogiczny sposób uruchomić inny zewnętrzny program w C#.

Process

Do rozpoczęcia procesu (uruchomienia polecania bash) zostanie wykorzystana metoda Start klasy Process z przestrzeni System.Diagnostics. Klasa Process odpowiada za dostęp do procesów lokalnych i zdalnych. W ramach instancji klasy Process mamy możliwość uruchamiania, zatrzymywania, kontrolowania i monitorowania procesu aplikacji.

Bash

Na początek należy sprawdzić ścieżkę do powłoki bash, którą przekażemy do właściwości FileName w ProcessStartInfo. Instancja ProcessStartInfo określa zbiór wartości, które są używane podczas uruchamiania procesu.

which bash

Po wykonaniu polecenia wypisało mi wartość /bin/bash na terminal. W celu prezentacji zaimplementowałem metodę ExecuteCommand w klasie Bash. Możemy także zamiast poniższej metody zaimplementować np. extension method dla stringa.

using System.Diagnostics;

public static class Bash
{
    public static (string output, string errorMsg) ExecuteCommand(string command)
    {
        var startInfo = new ProcessStartInfo
            {
                FileName = "/bin/bash",
                Arguments = $"-c \"{command}\"",
                RedirectStandardOutput = true,
                RedirectStandardError = true,
                UseShellExecute = false,
                CreateNoWindow = true
            };

        string output = null, errorMsg = null;

        using (var process = new Process() { StartInfo = startInfo})
        {
            process.Start();
            output = process.StandardOutput.ReadToEnd();
            errorMsg = process.StandardError.ReadToEnd();
            process.WaitForExit();
        }

        return (output, errorMsg);
    }
}

W bashu zostanie użyta opcja -c, która pozwala przekazać polecenie do wykonania, jako argument. W celu przechwycenie odpowiedzi/błędu i przekierowaniu na wyjście, należy w instancji ProcessStartInfo ustawić parametry RedirectStandardOutput i RedirectStandardError na wartość true. Zobaczmy jak to wygląda w praktyce. Do weryfikacji utworzyłem prostą aplikację konsolową w .NET Core i wywołam dwa polecenia. Pierwsze polecenie ma zwrócić status usługi proftpd (zakończy się sukcesem), a drugie polecenie ma zatrzymać nieistniejącą usługę abc (w tym przypadku otrzymamy błąd na wyjściu).

using System;
using System.Collections.Generic;

class Program
{
    static void Main(string[] args)
    {
        var bashCommands = new List()
        {
            "service proftpd status",
            "service abc stop",
        };

        foreach (var command in bashCommands)
        {
            var result = Bash.ExecuteCommand(command);

            if(String.IsNullOrEmpty(result.errorMsg) == false)
            {
                Console.ForegroundColor = ConsoleColor.DarkRed;
                Console.WriteLine(result.errorMsg);
            };

            if(String.IsNullOrEmpty(result.output) == false)
            {
                Console.ForegroundColor = ConsoleColor.DarkBlue;
                Console.WriteLine(result.output);
            };
        }

        Console.ReadKey();
    }
}

Czas teraz na sudo dotnet run i otrzymujemy poniższy wynik na terminalu.

Result output errorMsg

Miało być konkretnie, to czas w tym miejscu zakończyć wpis merytoryczny. Na koniec dodam, że kolejny wpis jeszcze w tym tygodniu. Zapraszam do śledzenia i odwiedzin bloga.