Can you help me improve this tiny usage() function?


#1

I want to create a usage() function using only the std. lib. I want it to show:

usage: appname filename

where appname is the name of the executable, but without any path. I also want it to work cross-platform. Here’s my version which seems v. verbose:

fn usage() {
    let appname = env::args().nth(0).unwrap();
    let appname = path::Path::new(&appname);
    let appname = appname.file_name().unwrap();
    eprintln!("usage: {} filename", appname.to_str().unwrap());
    ::std::process::exit(0);
}

Surely there’s a simpler, better way?


#2

Personally, I’d do:

fn usage() {
    let arg0: PathBuf = env::args().nth(0).unwrap().into();
    eprintln!("usage: {} filename", arg0.display());
    ::std::process::exit(0);
}

This skips the ugly parts around Path::file_name and is technically more correct. All command-line tools I’m aware of show the raw argv[0] in their usage message.


#3

I can’t think of any command line tools that give their paths as well as their executable names!

Anyway, I would still like to give just the filename & see if that can be done with less & nicer code than how I’m doing it now.


#4

PathBuf isn’t absolute though! If the command was executed with exactly program-name, then the PathBuf parsed will be simply program-name. By taking all of the first argument, you’ll behave correctly.

In fact, most unix programs I know act like this. If you have a unix system, try running:

/bin/ls --help

The result:

Usage: /bin/ls [OPTION]... [FILE]...

it’s absolute! Because it was invoked with an absolute path. If you just run ls, the usage is ls, just like your program will be if you use Path::display.


#5

As @daboross pointed out, most Unix programs do in fact show a bare argv[0] and you only don’t see a path because they are usually not invoked with one. That’s why I’d like to recommend once more that you follow general convention.

If you insist on only showing the last component of argv[0], I’m afraid your solution is about as short as it can get. I must admit, I’m a bit surprised that Path::file_name() returns an OsStr instead of another Path, but maybe someone else is aware of a good reason for that.