Documentation
#![allow(dead_code, unused_imports)]

extern crate encoding;

use std::error::Error;
use std::io::{BufReader, BufRead};
use std::process::{self, Command, Stdio};

use encoding::{Encoding, DecoderTrap, EncoderTrap};
use encoding::all::{GBK, UTF_8};

#[allow(dead_code)]
pub fn run_cmd() {
    // cmd_str可以是从输入流读取或从文件里读取
    let cmd_str: String;
    if cfg!(target_os = "windows") {
        // 这里不用\\而是/的话会被windows认为/tmp的/t是一个option而报错
        cmd_str = "dir d:\\program".to_string();
    } else {
        cmd_str = "ls -alh".to_string();
    }

    let output = if cfg!(target_os = "windows") {
        Command::new("cmd")
            .arg("/c")
            .arg(cmd_str)
            .arg("/n")
            .output()
            .expect("cmd exec error!")
    } else {
        Command::new("sh")
            .arg("-c")
            // .arg(cmd_str)
            .args(["ls","-alh"])
            .arg("/home/user ")
            // .args(["-a", "-l", "-h"])
            .output()
            .expect("sh exec error!")
    };

    // let output_str = String::from_utf8_lossy(&output.stdout);
    // let output_str = String::from_utf8(output.stdout).unwrap();
    // let output_str = String::from_utf8(output.stdout).unwrap();
    // let res = UTF_8.encode(&output_str, EncoderTrap::Strict).unwrap();
    // let out = GBK.decode(&res,DecoderTrap::Strict).unwrap();

    let out = if cfg!(target_os = "windows") {
        GBK.decode(&output.stdout, DecoderTrap::Strict).unwrap()
    } else {
        String::from_utf8(output.stdout).unwrap()
    };

    println!("run_cmd ret: {}", out);
}

// 不带参数命令
#[allow(dead_code)]
pub fn ls() -> Result<(), Box<dyn Error>> {
    let output = Command::new("ls").output()?;//.expect("执行异常,提示");
    let out = String::from_utf8(output.stdout).unwrap();
    println!("{}", out);
    Ok(())
}

// 带参数命令
#[allow(dead_code)]
pub fn ps() {
    // ps -q $$ -o %cpu,%mem
    let output = Command::new("ps")
        .arg("-q")
        .arg(process::id().to_string())
        .arg("-o")
        .arg("%cpu,%mem")
        .output()
        .unwrap();
    let out = String::from_utf8(output.stdout).unwrap();
    println!("{}", out);
}

// 复杂命令,直接扔进bash执行
#[allow(dead_code)]
pub unsafe fn xargs() {
    let mut cmd = "cat /proc/".to_string();
    cmd += &process::id().to_string();
    cmd += &"/stat | awk '{print $14,$15,$16,$17}'".to_string();
    let output = Command::new("bash")
        .arg("-c")
        .arg(cmd)
        .output()
        .unwrap();
    // let out = String::from_utf8(output.stdout).unwrap();
    let out = String::from_utf8_unchecked(output.stdout);
    println!("utime stime cutime cstime");
    println!("{}", out);
}

// 手动实现管道
#[allow(dead_code)]
pub fn time() {
    let mut fname = "/proc/".to_string();
    fname += &process::id().to_string();
    fname += &"/stat".to_string();
    let child = Command::new("cat")
        .arg(fname)
        .stdout(Stdio::piped())
        .spawn()
        .unwrap();
    let output = Command::new("awk")
        .arg("{print $14,$15,$16,$17}")
        .stdin(child.stdout.unwrap())
        .output()
        .unwrap();
    let out = String::from_utf8(output.stdout).unwrap();
    println!("utime stime cutime cstime");
    println!("{}", out);
}

// 获取运行中的命令的输出
#[allow(dead_code)]
pub fn iostat() {
    let child = Command::new("iostat")
        .arg("1")
        .stdout(Stdio::piped())
        .spawn()
        .unwrap();
    let mut out = BufReader::new(child.stdout.unwrap());
    let mut line = String::new();
    while let Ok(_) = out.read_line(&mut line) {
        println!("{}", line);
    }
}