在Rust中,如何使用颜色捕获过程输出?

时间:2016-12-30 10:30:44

标签: terminal console rust tty windows-console

我想从另一个进程(例如git status)捕获输出,处理它,并使用所有样式(粗体,斜体,下划线)和颜色进行打印。对我来说,进一步处理String非常重要,我只想打印它。

在Unix世界中,我认为这会涉及转义码,我不确定Windows世界,但它对我来说也很重要。

我知道如何在没有颜色的情况下这样做:

fn exec_git() -> String {
    let output = Command::new("git")
        .arg("status")
        .output()
        .expect("failed to execute process");

    String::from_utf8_lossy(&output.stdout).into_owned()
}

也许我应该使用spawn代替?

2 个答案:

答案 0 :(得分:2)

您可以使用git -c color.status=always status

强制git输出颜色
use std::process::Command;

fn main() {
    let output = Command::new("git")
        .arg("-c")
        .arg("color.status=always")
        .arg("status")
        .output()
        .expect("failed to execute process");

    let output = String::from_utf8_lossy(&output.stdout).into_owned();

    println!("{}", output);
}

仅适用于git status。对于更通用的解决方案,您必须检查程序文档并希望有一种方法可以强制彩色输出或检查程序如何确定是否应该输出颜色(例如检查COLORTERM环境变量)。

答案 1 :(得分:1)

您的代码已经有效

use std::process::Command;

fn main() {
    let output = Command::new("ls")
        .args(&["-l", "--color"])
        .env("LS_COLORS", "rs=0:di=38;5;27:mh=44;38;5;15")
        .output()
        .expect("Failed to execute");

    let sout = String::from_utf8(output.stdout).expect("Not UTF-8");
    let serr = String::from_utf8(output.stderr).expect("Not UTF-8");

    println!("{}", sout);
    println!("{}", serr);
}

打印输出:

total 68
-rw-r--r-- 4 root root 56158 Dec 23 00:00 [0m[44;38;5;15mCargo.lock[0m
-rw-rw-r-- 4 root root  2093 Dec  9 02:54 [44;38;5;15mCargo.toml[0m
drwxr-xr-x 1 root root  4096 Dec 30 15:24 [38;5;27msrc[0m
drwxr-xr-x 1 root root  4096 Dec 23 00:19 [38;5;27mtarget[0m

请注意,输出内部散布着一堆垃圾([44;[0m等)。这些是ANSI escape codes,终端模拟器会解释这些更改以下文本的颜色。

如果使用调试打印字符串,您将看到:

\u{1b}[0m\u{1b}[44;38;5;15mCargo.lock\u{1b}[0m

每个转义码都以ESC\u{1b})开头,后跟实际命令。您将不得不解析那些以便忽略它们以进行任何处理。

Windows不使用转义码(虽然maybe it can in Windows 10?),而是直接使用程序modifies the console it is connected to。输出中没有任何内容表示颜色。