3

I'm Brand new to Rust and I have been writing some practice apps. I am trying to accept command-line arguments using Clap. The code below takes a string and a number and prints them back out, as such:

$ cargo run "this is a test" -n11
this is a test
11

This works fine, but I want to be able to pipe input in place of the string like this:

$ echo "this is a test" | cargo run -- -n11
this is a test
11

Trying this yields:

error: The following required arguments were not provided:
    <INPUT>

USAGE:
    clap_sample --num <num> <INPUT>

For more information try --help

I can get around this using xargs like this:

$ echo "this is a test" | xargs -d '\n' cargo run -- -n11

Is there a better way to do this so that I can accept piped in strings while still using the -n option? Thanks in advance.

  use clap::{Arg, App}; 
  
  fn main() {
     let matches = App::new("Clap Sample")
         .arg(Arg::new("INPUT")
             .required(true)
             .index(1))
         .arg(Arg::new("num")
             .short('n')
             .long("num")
             .takes_value(true))
         .get_matches();
 
     let usr_string = matches.value_of("INPUT").unwrap();
     let key: u8 = matches.value_of("num").unwrap()
         .parse()
         .expect("NaN :(");
 
     println!("{}", usr_string);
     println!("{}", key);
 }

Bonus question: If I pipe a string in with xargs, I can have newlines in the string (with delimiter set to \0) and they are reflected in the output. If I pass it directly without echo and xargs, a literal '\n' shows in the output. Is there a way to have the newline represented when run directly?

sf11
  • 31
  • 2

1 Answers1

1

Your code is checking the command line for arguments, it is not reading standard input. To use xargs get move the input from the pipe to the command line is a good way of doing it.

echo -n "this is a test" | xargs cargo run -- -n11 

The other option you have is to change your program so it reads from stdin if no user_string argument was given. Here is a good starting point to read stdin https://doc.rust-lang.org/std/io/struct.Stdin.html

You should also replace the unwrap() here:

 let key: u8 = matches.value_of("num").unwrap()

with a check if the argument was given as it was not .required(true) for instance with a

if let Some(key) = matches.value_of("num")

or maybe with a unwrap_or("0")

Simson
  • 3,373
  • 2
  • 24
  • 38