うにてぃブログ

UnityやUnreal Engineの記事を書いていきます

【Unity】UnityEditor で動作する ターミナル を作成する

Mac OS でのみ動作確認を行いました

Process.Start を利用することで C# のコード上でも ターミナル(コマンドライン?)を実行することができるので
UnityEditor 上で ターミナル的なことができるか試してみました

ProcessStartInfo.filename にはフルパスが必要になってくるので実行ファイルの置いてある
位置を予め定義しておき、実行ファイルが存在するか検索しています

パイプ処理はこれだけだとできないので、現状1コマンドしか実行できません

f:id:hacchi_man:20200807003735p:plain:w300

コード

EditorWindow

using System.Diagnostics;
using System.Linq;
using UnityEditor;
using UnityEngine;

public class ExecCommandWindow : EditorWindow
{
    [MenuItem("Tools/Command")]
    private static void ShowWindow()
    {
        var window = GetWindow<ExecCommandWindow>();
        window.Show();
    }

    private string _command;
    private string _output;

    private void OnGUI()
    {
        _command = EditorGUILayout.TextField(_command);
        if (GUILayout.Button("Exec"))
        {
            _output = ExecCommand.Exec(_command);
        }

        EditorGUILayout.LabelField(_output, GUILayout.ExpandHeight(true));
    }
}

コマンド実行

public static class ExecCommand
{
    /// <summary>
    /// パス一覧
    /// 環境変数から取得しようとしたが
    /// </summary>
    private static readonly string[] checkPaths = new string[]
    {
        "/opt/local/bin",
        "/opt/local/sbin",
        "/usr/local/bin",
        "/usr/local/sbin",
        "/usr/bin",
        "/usr/sbin",
        "/bin",
        "/sbin",
    };
 
    private static string[] paths;
 
    static ExecCommand()
    {
        // 存在するパスだけを抽出
        paths = checkPaths.Where(System.IO.Directory.Exists).ToArray();
    }
 
    /// <summary>
    /// Path 内にバイナリがあるかチェック
    /// </summary>
    /// <param name="command"></param>
    /// <returns></returns>
    private static string FindPath(string command)
    {
        foreach (var path in paths)
        {
            var fullPath = System.IO.Path.Combine(path, command);

            if (System.IO.File.Exists(fullPath))
                return fullPath;
        }

        return string.Empty;
    }
 
    /// <summary>
    /// 内部でコマンドをパース
    /// </summary>
    /// <param name="command"></param>
    /// <returns></returns>
    public static string Exec(string command)
    {
        command = command.TrimStart();
        var index = command.IndexOf(' ');
        if (index < 0)
        {
            return Exec(command, "");
        }

        var c = command.Substring(0, index);
        var args = command.Substring(index + 1);
        return Exec(c, args);
    }
 
    public static string Exec(string command, string args)
    {
        var path = FindPath(command);

        if (string.IsNullOrEmpty(path))
            return $"File Not Exits. {command}";
 
        var progress = new ProcessStartInfo(path, args)
        {
            WindowStyle = ProcessWindowStyle.Hidden,
            UseShellExecute = false,
            RedirectStandardOutput = true
        };
 
        using (var p = Process.Start(progress))
        {
            var output = p.StandardOutput.ReadToEnd();
            p.WaitForExit(5000);

            return output;
        }
    }
}