จะเข้าถึงพารามิเตอร์บรรทัดคำสั่งได้อย่างไร


153

สนิมกวดวิชาไม่ได้อธิบายวิธีการใช้พารามิเตอร์จากบรรทัดคำสั่ง fn main()จะแสดงเฉพาะกับรายการพารามิเตอร์ที่ว่างเปล่าในตัวอย่างทั้งหมด

วิธีที่ถูกต้องในการเข้าถึงพารามิเตอร์บรรทัดคำสั่งmainคืออะไร?

คำตอบ:


168

คุณสามารถเข้าถึงอาร์กิวเมนต์บรรทัดคำสั่งโดยใช้std::env::argsหรือstd::env::args_osฟังก์ชั่น ทั้งสองฟังก์ชั่นส่งคืน iterator มากกว่าข้อโต้แย้ง อดีต iterates กว่าStrings (ที่ง่ายต่อการทำงานด้วย) แต่ตกใจถ้าหนึ่งในข้อโต้แย้งไม่ถูกต้องยูนิโค้ด หลังซ้ำกว่าOsStrings และไม่ต้องตกใจ

โปรดทราบว่าองค์ประกอบแรกของตัววนซ้ำเป็นชื่อของโปรแกรมเอง (นี่เป็นข้อตกลงในระบบปฏิบัติการหลักทั้งหมด) ดังนั้นอาร์กิวเมนต์แรกจึงเป็นองค์ประกอบที่วนซ้ำแล้วครั้งที่สอง

วิธีง่ายๆในการจัดการกับผลลัพธ์argsคือการแปลงเป็นVec:

use std::env;

fn main() {
    let args: Vec<_> = env::args().collect();
    if args.len() > 1 {
        println!("The first argument is {}", args[1]);
    }
}

คุณสามารถใช้กล่องเครื่องมือตัววนซ้ำมาตรฐานทั้งหมดเพื่อทำงานกับอาร์กิวเมนต์เหล่านี้ ตัวอย่างเช่นเพื่อดึงเฉพาะอาร์กิวเมนต์แรก:

use std::env;

fn main() {
    if let Some(arg1) = env::args().nth(1) {
        println!("The first argument is {}", arg1);
    }
}

คุณสามารถค้นหาไลบรารีบนcrates.ioเพื่อแยกอาร์กิวเมนต์บรรทัดคำสั่ง:

  • docopt : คุณเพียงแค่เขียนข้อความช่วยเหลือและรหัสการแยกวิเคราะห์จะถูกสร้างขึ้นสำหรับคุณ
  • ตบมือ : คุณอธิบายตัวเลือกที่คุณต้องการแยกวิเคราะห์โดยใช้ API ได้อย่างคล่องแคล่ว เร็วกว่า docopt และให้คุณควบคุมได้มากขึ้น
  • getopts : พอร์ตของไลบรารี C ยอดนิยม ระดับล่างและควบคุมได้มากขึ้น
  • structopt : สร้างขึ้นบน clap มันยิ่งเหมาะกับการใช้

2
ด้วยสนิม 0.8 คุณควรใช้เพียงprintln(args[0])
Leo Correa

6
ความคิดเห็นด้านบน (โดย @LeoCorrea / @ S4M) อ้างถึงคำตอบรุ่นเก่า รุ่นปัจจุบันของคำตอบประกอบด้วยข้อมูลที่ทันสมัยที่สุด
Nickolay

22

Docoptยังมีให้สำหรับ Rust ซึ่งสร้าง parser ให้คุณจากสตริงการใช้งาน เป็นโบนัสใน Rust สามารถใช้แมโครเพื่อสร้าง struct และทำการถอดรหัสตามประเภทโดยอัตโนมัติ:

docopt!(Args, "
Usage: cp [-a] SOURCE DEST
       cp [-a] SOURCE... DIR

Options:
    -a, --archive  Copy everything.
")

และคุณสามารถรับ args ด้วย:

let args: Args = Args::docopt().decode().unwrap_or_else(|e| e.exit());

README และเอกสารประกอบมีตัวอย่างการทำงานมากมาย

คำเตือน: ฉันเป็นหนึ่งในผู้เขียนของห้องสมุดนี้



10

สำหรับฉัน getopts มักจะรู้สึกในระดับต่ำเกินไปและ docopt.rs เป็นเวทย์มนตร์มากเกินไป ฉันต้องการบางสิ่งที่ชัดเจนและตรงไปตรงมาซึ่งยังคงมีคุณสมบัติทั้งหมดหากฉันต้องการ

นี่คือที่clap-rs เข้ามามีประโยชน์
รู้สึกเหมือนขัดแย้งจาก Python นี่คือตัวอย่างของลักษณะที่ปรากฏ:

let matches = App::new("myapp")
                      .version("1.0")
                      .author("Kevin K. <kbknapp@gmail.com>")
                      .about("Does awesome things")
                      .arg(Arg::with_name("CONFIG")
                           .short("c")
                           .long("config")
                           .help("Sets a custom config file")
                           .takes_value(true))
                      .arg(Arg::with_name("INPUT")
                           .help("Sets the input file to use")
                           .required(true)
                           .index(1))
                      .arg(Arg::with_name("debug")
                           .short("d")
                           .multiple(true)
                           .help("Sets the level of debugging information"))
                      .get_matches();

คุณสามารถเข้าถึงพารามิเตอร์ดังนี้:

println!("Using input file: {}", matches.value_of("INPUT").unwrap());

// Gets a value for config if supplied by user, or defaults to "default.conf"
let config = matches.value_of("CONFIG").unwrap_or("default.conf");
println!("Value for config: {}", config);

(คัดลอกมาจากเอกสารอย่างเป็นทางการ )


1
ฉันชอบ clap-rs ที่ให้คุณกำหนดส่วนต่อประสานในไฟล์ yaml นอกจากนี้ยังสร้างข้อความการใช้งานที่ดูดีมาก
Chuck Wooters

สิ่งนี้ช่วยให้ฉันตั้งค่าแอพ CLI ของฉันได้อย่างรวดเร็ว ขอบคุณ!
dimitarvp

4

ตั้งแต่เวอร์ชัน 0.8 / 0.9 เส้นทางที่ถูกต้องไปยังฟังก์ชัน args () จะเป็น::std::os::argsเช่น:

fn main() {
  let args: ~[~str] = ::std::os::args();
  println(args[0]);
}

ดูเหมือนว่าสนิมยังคงมีความผันผวนอยู่ในขณะนี้ด้วยมาตรฐาน IO ดังนั้นนี่อาจล้าสมัยไปอย่างรวดเร็ว


ขอบคุณสำหรับการอัพเดท! เดาว่าฉันจะต้องพิจารณาคำตอบที่ยอมรับอีกครั้งหลังจากปล่อย 1.0
shutefan

3

สนิมเปลี่ยนไปอีกครั้ง จะเลิกในความโปรดปรานของos::args() std::args()แต่std::args()ไม่ได้เป็นอาร์เรย์จะส่งกลับiterator คุณสามารถวนซ้ำอาร์กิวเมนต์บรรทัดคำสั่ง แต่ไม่สามารถเข้าถึงได้ด้วยตัวห้อย

http://doc.rust-lang.org/std/env/fn.args.html

หากคุณต้องการอาร์กิวเมนต์บรรทัดคำสั่งเป็นเวกเตอร์ของสตริงสิ่งนี้จะทำงานได้ทันที:

use std::env;
...
let args: Vec<String> = env::args().map(|s| s.into_string().unwrap()).collect();

สนิม - เรียนรู้ที่จะยอมรับความเจ็บปวดจากการเปลี่ยนแปลง


8
env::args().collect()ตอนนี้คุณต้องทำเท่านั้น
tshepang

2

สิ่งที่ @ barjak พูดว่าใช้งานได้กับสตริง แต่ถ้าคุณต้องการอาร์กิวเมนต์เป็นตัวเลข (ในกรณีนี้เป็น uint) คุณต้องแปลงดังนี้:

fn main() {
    let arg : ~[~str] = os::args();
    match uint::from_str(arg[1]){
         Some(x)=>io::println(fmt!("%u",someFunction(x))),
         None=>io::println("I need a real number")
    }
}

2

ตรวจสอบโครงสร้างเช่นกัน:

extern crate structopt;
#[macro_use]
extern crate structopt_derive;

use structopt::StructOpt;

#[derive(StructOpt, Debug)]
#[structopt(name = "example", about = "An example of StructOpt usage.")]
struct Opt {
    /// A flag, true if used in the command line.
    #[structopt(short = "d", long = "debug", help = "Activate debug mode")]
    debug: bool,

    /// An argument of type float, with a default value.
    #[structopt(short = "s", long = "speed", help = "Set speed", default_value = "42")]
    speed: f64,

    /// Needed parameter, the first on the command line.
    #[structopt(help = "Input file")]
    input: String,

    /// An optional parameter, will be `None` if not present on the
    /// command line.
    #[structopt(help = "Output file, stdout if not present")]
    output: Option<String>,
}

fn main() {
    let opt = Opt::from_args();
    println!("{:?}", opt);
}

https://github.com/TeXitoi/structopt


1

ในฐานะที่เป็นรุ่น Rust ใหม่ (สนิม> 0.10 / 11) ไวยากรณ์อาร์เรย์จะไม่ทำงาน คุณจะต้องใช้วิธีการรับ

[แก้ไข] ไวยากรณ์ของอาร์เรย์ทำงานได้อีกครั้งในตอนกลางคืน ดังนั้นคุณสามารถเลือกระหว่าง getter หรือ index array

use std::os;

fn main() {
  let args = os::args();
  println!("{}", args.get(1));
}

// Compile
 rustc args.rs && ./args hello-world // returns hello-world

นี่คือคำสั่งที่ล้าสมัย Rust night ล่าสุดสนับสนุนการสร้างดัชนีไวยากรณ์บนVecs ฉันคิดว่ามันอยู่ที่นั่นประมาณหนึ่งเดือน ดูตัวอย่างนี้
Vladimir Matveev

1

Rust ได้พัฒนาขึ้นตั้งแต่คำตอบของ Calvin ตั้งแต่เดือนพฤษภาคม 2013 ตอนนี้ใครจะแยกอาร์กิวเมนต์บรรทัดคำสั่งด้วยas_slice():

use std::os;

fn seen_arg(x: uint)
{       
    println!("you passed me {}", x);
}
fn main() {
    let args = os::args();
    let args = args.as_slice();
    let nitems = {
            if args.len() == 2 {
                    from_str::<uint>(args[1].as_slice()).unwrap()
            } else {
                    10000
            }
    };

    seen_arg(nitems);
}

เพียงบันทึก: as_slice()ไม่มีอยู่อีกต่อไปและ&argsควรใช้แทน
Slava Semushin

1

บทRust หนังสือ "No stdlib"ครอบคลุมถึงวิธีการเข้าถึงพารามิเตอร์บรรทัดคำสั่ง (วิธีอื่น)

// Entry point for this program
#[start]
fn start(_argc: isize, _argv: *const *const u8) -> isize {
    0
}

ตอนนี้ตัวอย่างเช่นไม่ยังมีซึ่งผมคิดว่าวิธีการที่ปกติห้องสมุดมาตรฐานจะมีจุดเริ่มต้นที่เป็นจริงสำหรับไบนารีของคุณและเรียกฟังก์ชั่นระดับโลกที่เรียกว่า#![no_std] main()ตัวเลือกหนึ่งคือการ 'พิการชิมด้วยmain #![no_main]ซึ่งถ้าฉันไม่เข้าใจผิดก็คือพูดกับคอมไพเลอร์ว่าคุณสามารถควบคุมการเริ่มต้นโปรแกรมของคุณได้อย่างเต็มที่

#![no_std]
#![no_main]

#[no_mangle] // ensure that this symbol is called `main` in the output
pub extern fn main(argc: isize, argv: *const *const u8) -> isize {
    0
}

ฉันไม่คิดว่านี่เป็นวิธีที่ 'ดี' ในการทำสิ่งต่าง ๆ หากคุณต้องการทำคืออ่านอาร์กิวเมนต์บรรทัดคำสั่ง std::osโมดูลที่กล่าวถึงในคำตอบอื่น ๆ น่าจะเป็นวิธีที่ดีมากในการทำสิ่ง ฉันโพสต์คำตอบนี้เพื่อประโยชน์ของความสำเร็จ

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.