Выбрать главу

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<Vec<Path>>`

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`

`rmdir a/c/d`

And the final state of the a directory is:

$ tree a

a

|-- b.txt

`-- c

`-- b.txt -> ../b.txt

1 directory, 2 files

An alternative way to define the function cat is with ? notation:

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

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

let mut s = String::new();

f.read_to_string(&mut s)?;

Ok(s)

}

cfg!

The command line arguments can be accessed using std::env::args, which returns an iterator that yields a String for each argument:

use std::env;

fn main() {

let args: Vec<String> = env::args().collect();

// The first argument is the path that was used to call the program.

println!("My path is {}.", args[0]);

// The rest of the arguments are the passed command line parameters.

// Call the program like this:

// $ ./args arg1 arg2

println!("I got {:?} arguments: {:?}.", args.len() - 1, &args[1..]);

}

הההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההה

XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

$ ./args 1 2 3

My path is ./args.

I got 3 arguments: ["1", "2", "3"].

Alternatively, there are numerous crates that can provide extra functionality when creating command-line applications. The Rust Cookbook exhibits best practices on how to use one of the more popular command line argument crates, clap.

Matching can be used to parse simple arguments:

use std::env;

fn increase(number: i32) {

println!("{}", number + 1);

}

fn decrease(number: i32) {

println!("{}", number - 1);

}

fn help() {

println!("usage:

match_args <string>

Check whether given string is the answer.

match_args {{increase|decrease}} <integer>

Increase or decrease given integer by one.");

}

fn main() {

let args: Vec<String> = env::args().collect();

match args.len() {

// no arguments passed

1 => {

println!("My name is 'match_args'. Try passing some arguments!");

},

// one argument passed

2 => {

match args[1].parse() {

Ok(42) => println!("This is the answer!"),

_ => println!("This is not the answer."),

}

},

// one command and one argument passed

3 => {

let cmd = &args[1];

let num = &args[2];

// parse the number

let number: i32 = match num.parse() {

Ok(n) => {

n

},

Err(_) => {

eprintln!("error: second argument not an integer");

help();