C#执行本机shell命令 | 远程服务器shell命令 | 上传文件到服务器 | 从服务器下载文件

本文介绍了如何使用C#进行本机命令行操作,包括使用Nuget包 CliWrap 和 Furion.Tools.CommandLine 实现命令执行及监听输出。同时,展示了通过SSH.NET库实现远程服务器的SSH和SFTP操作,如文件上传、下载和执行远程命令。提供了实用的辅助类以简化代码。
摘要由CSDN通过智能技术生成

Nuget

CliWrap
---> 本机命令包装   https://github.com/Tyrrrz/CliWrap

SSH.NET
---> C#版本的 SSH, SFTP 

Furion.Tools.CommandLine
---> 便捷的编写命令行工具

在这里插入图片描述

执行本机命令

例子

// 命令工作的目录
var buildFolderPath = @"E:\ReactProject\build\";

// 执行压缩命令
NativeCmdUtils.ExecCmdAndListenAsync(
      "E:\\Software\\7-Zip\\7z.exe", "a publish.7z .", 
      buildFolderPath
   )
   .Wait();

帮助类

using System;
using System.Text;
using System.Threading.Tasks;

using CliWrap.EventStream;

using Furion.Tools.CommandLine;

using Renci.SshNet;

using Cmd = CliWrap;

namespace JJDSPublish
{
    public static class NativeCmdUtils
    {
        public static async Task ExecCmdAndListenAsync(string filePath, string arg, string workingDir)
        {
            var cmd = CliWrap.Cli.Wrap(filePath).WithArguments(arg)
                .WithWorkingDirectory(workingDir);

            await foreach (var cmdEvent in cmd.ListenAsync())
            {
                switch (cmdEvent)
                {
                    case StartedCommandEvent started:
                        //Cli.WriteLine($"Process started; ID: {started.ProcessId}");
                        break;
                    case StandardOutputCommandEvent stdOut:
                        Cli.WriteLine($"{stdOut.Text}", ConsoleColor.Green);
                        break;
                    case StandardErrorCommandEvent stdErr:
                        Cli.WriteLine($"{stdErr.Text}", ConsoleColor.Red);
                        break;
                    case ExitedCommandEvent exited:
                        //Cli.WriteLine($"Process exited; Code: {exited.ExitCode}");
                        if (exited.ExitCode != 0)
                        {
                            throw new Exception("执行命令失败");
                        }
                        break;
                }
            }

        }

        /// <summary>
        /// https://github.com/Tyrrrz/CliWrap
        /// </summary>   
        public static void ExecCmd(string filePath, string arg, string workingDir)
        {

            var stdOutBuffer = new StringBuilder();
            var stdErrBuffer = new StringBuilder();

            var cmd = Cmd.Cli.Wrap(filePath).WithArguments(arg)
                .WithWorkingDirectory(workingDir)
                .WithStandardOutputPipe(Cmd.PipeTarget.ToStringBuilder(stdOutBuffer))
                .WithStandardErrorPipe(Cmd.PipeTarget.ToStringBuilder(stdErrBuffer))
                .ExecuteAsync().GetAwaiter().GetResult();
            var stdOut = stdOutBuffer.ToString();
            var stdErr = stdErrBuffer.ToString();

            // 如果失败
            if (cmd.ExitCode != 0 || !string.IsNullOrWhiteSpace(stdErr) || string.IsNullOrWhiteSpace(stdOut))
            {               
                throw new Exception("执行失败:"+stdErr);
            }

            // 输出所有日志
            Cli.Success(stdOut);
        }


    }
}

操作远程服务器

例子

上传文件 (下载文件类似)

// ip : 端口 , 用户名 , 密码  (逗号分隔)
var remoteInfo = "1.117.xxx.xxx:22,root,xxxxxx";

var zipFilePath = @"E:\Work\publish.7z";
var remoteFilePath = "/data/publish.7z";

RemoteServerUtils.GetSftpRemoteClient(remoteInfo)
                .UploadFile(
                    zipFilePath,
                    remoteFilePath
                )
                .Disconnect();

执行远程命令

// ip : 端口 , 用户名 , 密码  (逗号分隔)
var remoteInfo = "1.117.xxx.xxx:22,root,xxxxxx";
var remoteClient = RemoteServerUtils.GetCmdRemoteClient(remoteInfo);

remoteClient.RunCmd("cd /data/nginx/html/ && 7z x publish.7z -o./jjds && chmod 777 -R  /data/nginx/html/jjds/ && docker start nginx && rm -r -f /data/nginx/html/publish.7z");


帮助类

using System;
using System.Data;
using System.IO;
using System.Threading;
using System.Threading.Tasks;

using Furion.Tools.CommandLine;

using Renci.SshNet;

namespace JJDSPublish
{
    /// <summary>
    /// 由于ssh和sftp端口(默认:22)可以改为监听不同的端口,所以工具类中两种操作分开实现
    /// </summary>
    public class RemoteServerUtils
    {
        /// <summary>
        ///  执行命令
        /// </summary>
        /// <param name="remoteInfo"> 使用逗号分隔,例如: 1.117.xxx.xxx:22,username,password</param>
        /// <returns></returns>
        public static RemoteCmd GetCmdRemoteClient(string remoteInfo)
        {
            return new RemoteCmd(remoteInfo);
        }

        /// <summary>
        ///  文件操作
        /// </summary>
        /// <param name="remoteInfo">使用逗号分隔,例如: 1.117.xxx.xxx:22,username,password</param>
        /// <returns></returns>
        public static RemoteSftp GetSftpRemoteClient(string remoteInfo)
        {
            return new RemoteSftp(remoteInfo);
        }

        #region 封装

        /// <summary>
        /// 解析 服务器信息字符串
        /// </summary>
        private static RemoteServerInfo GetServerInfo(string serverInfo)
        {
            var info = serverInfo.Split(",");
            var hostInfo = info[0].Split(":");

            return new RemoteServerInfo()
            {
                Host = hostInfo[0],
                Port = int.Parse(hostInfo[1]),
                UserName = info[1],
                PassWord = info[2]
            };
        }

        /// <summary>
        /// SSH
        /// </summary>
        public class RemoteCmd
        {
            private readonly SshClient _sshClient;

            public RemoteCmd(string remoteInfo)
            {
                var serveInfo = GetServerInfo(remoteInfo);
                // 请勿使用using,using会在构造函数结束后,自动释放连接,这样就无法执行命令了.请使用 Disconnect 手动释放
                var sshClient =
                    new SshClient(serveInfo.Host, serveInfo.Port, serveInfo.UserName, serveInfo.PassWord);
                sshClient.Connect();
                if (!sshClient.IsConnected)
                {
                    throw new Exception("sshClient 未连接");
                }

                this._sshClient = sshClient;
            }

            /// <summary>
            /// 断开连接
            /// </summary>
            public void Disconnect()
            {
                _sshClient.Disconnect();
                _sshClient.Dispose();
            }

            public RemoteCmd RunCmd(string cmdStr)
            {
                var cmd = _sshClient.RunCommand(cmdStr);

                if (cmd.ExitStatus != 0)
                {
                    throw new Exception(cmd.Error);
                }

                Cli.Success(cmd.Result);

                return this;
            }
        }

        /// <summary>
        /// SFTP
        /// </summary>
        public class RemoteSftp
        {
            private readonly SftpClient _sftpClient;

            // 锁
            private static int usingResource = 0;

            public RemoteSftp(string remoteInfo)
            {
                var serveInfo = GetServerInfo(remoteInfo);
                var sftpClient =
                    new SftpClient(serveInfo.Host, serveInfo.Port, serveInfo.UserName, serveInfo.PassWord);
                sftpClient.Connect();
                if (!sftpClient.IsConnected)
                {
                    throw new Exception("sftpClient 未连接");
                }

                _sftpClient = sftpClient;
            }

            /// <summary>
            /// 断开连接
            /// </summary>
            public void Disconnect()
            {
                _sftpClient.Disconnect();
                _sftpClient.Dispose();
            }

            /// <summary>
            /// 上传
            /// </summary>           
            public RemoteSftp UploadFile(string inputFilePath, string remoteFilePath)
            {
                Cli.EmptyLine();
                var file = File.Open(inputFilePath, FileMode.Open);
                var fileSize = HumanReadableFilesize(file.Length);

                _sftpClient.UploadFile(file,
                    remoteFilePath, (v) =>
                    {
                        if (0 == Interlocked.Exchange(ref usingResource, 1))
                        {
                            var bfb = Math.Round((double.Parse(v + "") / file.Length) * 100, 2) + "%";
                            Cli.Write($"正在上传: {HumanReadableFilesize(v)}/ {fileSize} --- {bfb}", fillLine: true);
                            Thread.Sleep(3000);
                            CliExtend.ResetLine();
                            Interlocked.Exchange(ref usingResource, 0);
                        }
                    });
                Cli.EmptyLine();
                Cli.WriteLine("上传成功:" + remoteFilePath);
                return this;
            }

            /// <summary>
            /// 下载
            /// </summary>
            public RemoteSftp DownloadFile(string remoteFilePath, string outputFilePath)
            {
                Cli.EmptyLine();
                using var stream = File.Open(outputFilePath, FileMode.OpenOrCreate);
                _sftpClient.DownloadFile(remoteFilePath, stream,
                    (v) =>
                    {
                        if (0 == Interlocked.Exchange(ref usingResource, 1))
                        {                            
                            Cli.Write("正在下载:" + HumanReadableFilesize(v));
                            Thread.Sleep(3000);
                            CliExtend.ResetLine();
                            Interlocked.Exchange(ref usingResource, 0);
                        }
                    });
                Cli.EmptyLine();
                Cli.WriteLine("下载成功:" + outputFilePath);
                return this;
            }

            /// <summary>
            /// 人类可读的文件大小格式
            /// </summary>
            private String HumanReadableFilesize(double size)
            {
                String[] units = new String[] { "B", "KB", "MB", "GB", "TB", "PB" };
                double mod = 1024.0;
                int i = 0;
                while (size >= mod)
                {
                    size /= mod;
                    i++;
                }

                return Math.Round(size, 3) + units[i];
            }
        }

        /// <summary>
        /// 远程服务器信息
        /// </summary>
        private class RemoteServerInfo
        {
            public string Host { get; set; }
            public int Port { get; set; }
            public string UserName { get; set; }
            public string PassWord { get; set; }
        }

        #endregion
    }
}


CliExtend

using System;

namespace Furion.Tools.CommandLine
{
    public static class CliExtend
    {
        public static void WriteSplitLine(string content = "")
        {
            if (content != "")
            {
                content = " " + content + " ";
            }

            Cli.EmptyLine();
            Cli.WriteLine($"==========================={content}===========================", ConsoleColor.Gray);
            Cli.EmptyLine();
        }

        public static void ResetLine()
        {
            Console.SetCursorPosition(0, Console.CursorTop);
        }
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值