Rust by Example — страница 60 из 66

Pipes

The std::Child struct represents a running child process, and exposes the stdin, stdout and stderr handles for interaction with the underlying process via pipes.

use std::io::prelude::*;

use std::process::{Command, Stdio};


static PANGRAM: &'static str =

"the quick brown fox jumped over the lazy dog\n";


fn main() {

// Spawn the `wc` command

let process = match Command::new("wc")

.stdin(Stdio::piped())

.stdout(Stdio::piped())

.spawn() {

Err(why) => panic!("couldn't spawn wc: {}", why),

Ok(process) => process,

};


// Write a string to the `stdin` of `wc`.

//

// `stdin` has type `Option`, but since we know this instance

// must have one, we can directly `unwrap` it.

match process.stdin.unwrap().write_all(PANGRAM.as_bytes()) {

Err(why) => panic!("couldn't write to wc stdin: {}", why),

Ok(_) => println!("sent pangram to wc"),

}


// Because `stdin` does not live after the above calls, it is `drop`ed,

// and the pipe is closed.

//

// This is very important, otherwise `wc` wouldn't start processing the

// input we just sent.


// The `stdout` field also has type `Option` so must be unwrapped.

let mut s = String::new();

match process.stdout.unwrap().read_to_string(&mut s) {

Err(why) => panic!("couldn't read wc stdout: {}", why),

Ok(_) => print!("wc responded with:\n{}", s),

}

}

Wait

If you'd like to wait for a process::Child to finish, you must call Child::wait, which will return a process::ExitStatus.

use std::process::Command;


fn main() {

let mut child = Command::new("sleep").arg("5").spawn().unwrap();

let _result = child.wait().unwrap();


println!("reached end of main");

}

$ rustc wait.rs && ./wait

# `wait` keeps running for 5 seconds until the `sleep 5` command finishes

reached end of main

Filesystem Operations

The std::fs module contains several functions that deal with the filesystem.

use std::fs;

use std::fs::{File, OpenOptions};

use std::io;

use std::io::prelude::*;

use std::os::unix;

use std::path::Path;


// A simple implementation of `% cat path`

fn cat(path: &Path) -> io::Result {

let mut f = File::open(path)?;

let mut s = String::new();

match f.read_to_string(&mut s) {

Ok(_) => Ok(s),

Err(e) => Err(e),

}

}


// A simple implementation of `% echo s > path`

fn echo(s: &str, path: &Path) -> io::Result<()> {

let mut f = File::create(path)?;


f.write_all(s.as_bytes())

}


// A simple implementation of `% touch path` (ignores existing files)

fn touch(path: &Path) -> io::Result<()> {

match OpenOptions::new().create(true).write(true).open(path) {

Ok(_) => Ok(()),

Err(e) => Err(e),

}

}


fn main() {

println!("`mkdir a`");

// Create a directory, returns `io::Result<()>`

match fs::create_dir("a") {

Err(why) => println!("! {:?}", why.kind()),

Ok(_) => {},

}


println!("`echo hello > a/b.txt`");

// The previous match can be simplified using the `unwrap_or_else` method

echo("hello", &Path::new("a/b.txt")).unwrap_or_else(|why| {

println!("! {:?}", why.kind());

});


println!("`mkdir -p a/c/d`");

// Recursively create a directory, returns `io::Result<()>`

fs::create_dir_all("a/c/d").unwrap_or_else(|why| {

println!("! {:?}", why.kind());

});


println!("`touch a/c/e.txt`");

touch(&Path::new("a/c/e.txt")).unwrap_or_else(|why| {

println!("! {:?}", why.kind());

});


println!("`ln -s ../b.txt a/c/b.txt`");

// Create a symbolic link, returns `io::Result<()>`

if cfg!(target_family = "unix") {

unix::fs::symlink("../b.txt", "a/c/b.txt").unwrap_or_else(|why| {

println!("! {:?}", why.kind());

});

}


println!("`cat a/c/b.txt`");

match cat(&Path::new("a/c/b.txt")) {

Err(why) => println!("! {:?}", why.kind()),

Ok(s) => println!("> {}", s),

}


println!("`ls a`");

// Read the contents of a directory, returns `io::Result>`

match fs::read_dir("a") {

Err(why) => println!("! {:?}", why.kind()),

Ok(paths) => for path in paths {

println!("> {:?}", path.unwrap().path());

},

}


println!("`rm a/c/e.txt`");

// Remove a file, returns `io::Result<()>`

fs::remove_file("a/c/e.txt").unwrap_or_else(|why| {

println!("! {:?}", why.kind());

});


println!("`rmdir a/c/d`");

// Remove an empty directory, returns `io::Result<()>`

fs::remove_dir("a/c/d").unwrap_or_else(|why| {

println!("! {:?}", why.kind());

});

}


Here's the expected successful output:

$ rustc fs.rs && ./fs

`mkdir a`

`echo hello > a/b.txt`

`mkdir -p a/c/d`

`touch a/c/e.txt`

`ln -s ../b.txt a/c/b.txt`

`cat a/c/b.txt`

> hello

`ls a`

> "a/b.txt"

> "a/c"

`rm a/c/e.txt`