【问题标题】:Plink returning unwanted characters via C#Plink 通过 C# 返回不需要的字符
【发布时间】:2016-09-06 21:20:19
【问题描述】:

在通过 C# 使用 Plink 时,我在结果前后收到不需要的字符:

命令:

ls -l */informatica/tgtdynamicparams*.out | grep vaulttest| grep 'Sep  1'|awk '{print $9}' | sort

Linux 结果:

aaco/informatica/tgtdynamicparams2269885_CHECK_REF_COMPANY.out
cdph/informatica/tgtdynamicparams2225704_CDPHDRUGRECON.out
cdph/informatica/tgtdynamicparams2225704_CDPHELIGRECON.out
merh/informatica/tgtdynamicparams3454321_OPEN_TEST.out
merh/informatica/tgtdynamicparams3454322_OPEN_TEST2.out

C# 通过 Plink 结果:

[01;32mcdph/informatica/tgtdynamicparams2225704_CDPHDRUGRECON.out[0m
[01;32mcdph/informatica/tgtdynamicparams2225704_CDPHELIGRECON.out[0m
[01;32mmerh/informatica/tgtdynamicparams3454321_OPEN_TEST.out[0m
[01;32mmerh/informatica/tgtdynamicparams3454322_OPEN_TEST2.out[0m
[0m[01;32maaco/informatica/tgtdynamicparams2269885_CHECK_REF_COMPANY.out[0m

我尝试了以下方法,但没有任何运气:

StandardOutputEncoding = Encoding.UTF8
StandardOutputEncoding = Encoding.ASCII
StandardOutputEncoding = Encoding.DEFAULT

这是我正在使用的代码。我看到了类似问题的回复,建议使用 ssh.net,但我不允许使用它必须是 Plink。

private string GetFileNames = @"ls -l */informatica/tgtdynamicparams*.out 
                             | grep vaulttest| grep 'Sep  1'
                             | awk '{print $9}' 
                             | sort";

GetProcessesCommands = new [] {
                               @"cd /src/trs/runjobs",
                               GetFileNames
                              };
Request(ServerName, UserName, Password, GetProcessesCommands);

这样称呼:

private void Request(string remoteHost, string userName, string password, IEnumerable<string> lstCommands)
{
    try
    {
        var psi = new ProcessStartInfo
        {
            FileName = FormInformatiKill.PropFile.Plink,
            Arguments = string.Format("-ssh {0}@{1} -pw {2}", userName, remoteHost, password),
            RedirectStandardError = true,
            RedirectStandardOutput = true,
            RedirectStandardInput = true,
            UseShellExecute = false,
            CreateNoWindow = true,
            StandardOutputEncoding = Encoding.UTF8
        };

        var p = Process.Start(psi);
        _mObjLock = new object();
        _mBlnDoRead = true;

        if( p == null ) return;
        AsyncReadFeedback(p.StandardOutput); // start the async read of stdout

        var strw = p.StandardInput;

        foreach( var cmd in lstCommands )
        {
            strw.WriteLine( cmd ); // send commands 
        }
        strw.WriteLine("exit"); // send exit command at the end

        p.WaitForExit(); // block thread until remote operations are done  
    }
    catch (Exception e)
    {
        Console.WriteLine(e.Message);
        Console.WriteLine(e.StackTrace);
    }
}

private void AsyncReadFeedback(StreamReader strr)
{
    var trdr = new Thread(ReadFeedback);
    trdr.Start(strr);
}

private void ReadFeedback(object objStreamReader)
{
    var strr = (StreamReader) objStreamReader;
    while (!strr.EndOfStream && _mBlnDoRead)
    {
        var line = strr.ReadLine();
        // lock the feedback buffer (since we don't want some messy stdout/err mix string in the end)
        lock (_mObjLock)
        {
            if( line != null ) ListOfFilesResults.Add(line.Trim());
        }
    }
}

我试过Trim()。我什至花时间试图删除我不想要的字符,但似乎有比我编码更多的可能性。

【问题讨论】:

  • 那些是"terminal escape codes"(这与编码无关,尽管它会受到程序如何检测控制台模式的影响),用于颜色等。
  • 在这种情况下,颜色生成可能来自ls 命令。使用ls --color=never -l ..
  • user2864740 ...完美运行。谢谢!我如何给你信用?

标签: c# linux plink


【解决方案1】:

谢谢用户2864740! 我添加了 --color=never 并且那些该死的字符消失了。

            private const string GetFileNames = "ls --color=never -l */informatica/tgtdynamicparams*.out  " +
                                        "| grep vaulttest " +
                                        "| grep 'Sep  1' " +
                                        "| awk '{print $9}' " +
                                        "| sort";

【讨论】:

    【解决方案2】:

    那些是ANSI escape codes

    虽然使用--color=never 可能会有所帮助,但根本问题在于,您运行 Plink 的方式(使用标准输入提供命令),使其使用交互式会话。现在的大多数系统都配置为对目录列表(和其他内容)使用花哨的格式,以使交互式会话更加人性化。

    在您的情况下,没有人参与,因此您应该使用非交互式会话。

    有两种方法可以做到这一点:

    • 在 Plink 命令行上提供命令(而不是使用标准输入提供),例如:

      plink.exe -ssh username@example.com -pw password "ls -l ... | grep ... | sort"
      

      此语法隐式强制使用非交互模式。

    • 或使用-T switch 明确强制非交互模式:

      plink.exe -ssh username@example.com -pw password -T
      

      此语法允许您使用标准输入继续输入命令。

    使用非交互式会话(在正确配置的系统上)可以避免交互式会话的所有麻烦(不仅仅是--color)。所以这是一种更通用的解决方案。


    如果这对您不起作用,那一定是因为您的服务器配置错误并将ls 别名化为使用--color,即使对于非交互式会话也是如此。

    如果您无法修复服务器,我建议您同时使用非交互式会话(以避免其他可能的麻烦)和--color=never 开关。可能比使用--color=never 更好的解决方案是使用unalias ls

    【讨论】:

    • 我试图将 -T 添加到我的代码中,但没有效果。所有这些都是通过 C# 中的 Plink 运行的。我将标志 UseShellExecute 设置为 false。 ` Arguments = string.Format("-ssh {0}@{1} -pw {2} -T ", userName, remoteHost, password), RedirectStandardOutput = true, RedirectStandardInput = true, UseShellExecute = false, CreateNoWindow = true }; `
    • 为我工作。虽然我不得不用.Write(... + "\n") 替换.WriteLine(...) 调用,因为WriteLine 使用\r\n,非交互式*nix 会话无法处理。如果这对您不起作用,那一定是因为您的服务器配置错误并将ls 别名为使用--color,即使对于非交互式会话也是如此。
    • 你是对的。我追溯了我的 .bashrc,它使用 /etc/bashrc 来设置交互式会话。我从我的版本中删除了那个调用,问题就消失了。不幸的是,生产版本使用的用户我无法更改他们的会话变量,它包括交互式会话。感谢您抽出宝贵时间提供帮助!
    • 不客气。我已经在我的回答中添加了这个和其他建议。
    猜你喜欢
    • 2017-09-28
    • 2014-02-22
    • 1970-01-01
    • 2018-11-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多