Oxidising the Command Line
July 24. 2019
mattpro@yelp.com
Rust at Yelp Yelp connects Users with Great Local Businesses
184 million reviews
35 million unique devices per month
Yelp has developed a framework in Rust for real-time
A/B testing. It’s used across all Yelp websites and
apps, and experiment subjects range from UX to
internal infrastructure. Rust was chosen because it’s as
fast as C (cheap to run) and safer than C (cheap to
maintain).
5,550 employees worldwide
Oxidising the
Command Line
Basic toolbox for writing CLI utilities:
Handling Broken Pipes
Reading input by byte
Reading lines
Reading input from stdin or files
Handling non-UTF8 arguments
Oxidising the
Command Line
Handling Broken Pipes
fn main() {
match std::env::args().nth(1) {
Some(y) => loop {
println!("{}", y)
}
None => loop {
println!("y")
}
}
}
% target/debug/yes | /usr/bin/head
y
y
y
y
y
y
y
y
y
y
thread 'main' panicked at 'failed printing to stdout: Broken pipe (os error 32)',
libstd/io/stdio.rs:700:9
note: Run with `RUST_BACKTRACE=1` environment variable to display a backtrace.
% echo "${pipestatus[1]}"
101
% /usr/bin/yes | /usr/bin/head
y
y
y
y
y
y
y
y
y
y
% echo "${pipestatus[1]}"
141
#define SIGHUP 1 /* hangup */
#define SIGINT 2 /* interrupt */
#define SIGQUIT 3 /* quit */
#define SIGILL 4 /* illegal instruction (not reset when caught) */
#define SIGTRAP 5 /* trace trap (not reset when caught) */
#define SIGABRT 6 /* abort() */
#define SIGFPE 8 /* floating point exception */
#define SIGKILL 9 /* kill (cannot be caught or ignored) */
#define SIGBUS 10 /* bus error */
#define SIGSEGV 11 /* segmentation violation */
#define SIGSYS 12 /* bad argument to system call */
#define SIGPIPE 13 /* write on a pipe with no one to read it */
#define SIGALRM 14 /* alarm clock */
#define SIGTERM 15 /* software termination signal from kill */
#define SIGURG 16 /* urgent condition on IO channel */
#define SIGSTOP 17 /* sendable stop signal not from tty */
#define SIGTSTP 18 /* stop signal from tty */
#define SIGCONT 19 /* continue a stopped process */
#define SIGCHLD 20 /* to parent on child stop or exit */
...
use std::io::{stdout, Write};
fn main() {
let mut out = stdout();
match std::env::args().nth(1) {
Some(y) => loop {
writeln!(out, "{}", y).unwrap()
}
None => loop {
writeln!(out, "y").unwrap()
}
}
}
% target/debug/yes | /usr/bin/head
y
y
y
y
y
y
y
y
y
y
thread 'main' panicked at 'called `Result::unwrap()` on an `Err` value: Os { code: 32,
kind: BrokenPipe, message: "Broken pipe" }', libcore/result.rs:1009:5
use std::io::{stdout, ErrorKind::BrokenPipe, Write};
fn main() {
let mut out = stdout();
let arg = std::env::args().nth(1);
let y = match arg.as_ref() {
Some(a) => a,
None => "y",
};
loop {
if let Err(e) = writeln!(out, "{}", y) {
if e.kind() == BrokenPipe {
std::process::exit(141)
} else {
panic!("{:?}", e)
}
}
}
}
% target/debug/yes | /usr/bin/head
y
y
y
y
y
y
y
y
y
y
% echo "${pipestatus[1]}"
141
Oxidising the
Command Line
Reading input by byte
Trait std::io::Read
fn bytes(self) -> Bytes<Self>
Transforms this Read instance to an Iterator over its bytes.
The returned type implements Iterator where the Item is Result<u8,io::Error>. The yielded item is Ok if a
byte was successfully read and Err otherwise. EOF is mapped to returning None from this iterator.
use std::io::{stdin, stdout, Read, Write};
fn main() {
let fp = stdin().bytes();
let mut out = stdout();
let mut cnt = 10;
for ch in fp {
if let Ok(b) = ch {
out.write(b).unwrap();
if b == b'n' {
cnt -= 1
}
} else { // Err
cnt -= 1
}
if cnt == 0 {
break
}
}
}
error[E0308]: mismatched types
--> src/bin/head.rs:13:23
|
13 | out.write(b).unwrap();
| ^ expected &[u8], found u8
|
= note: expected type `&[u8]`
found type `u8`
Trait std::io::Write
fn write(&mut self, buf: &[u8]) -> Result<usize>
Module std::slice
pub fn from_ref<T>(s: &T) -> &[T]
Converts a reference to T into a slice of length 1 (without copying).
use std::io::{stdin, stdout, Read, Write};
fn main() {
let fp = stdin().bytes();
let mut out = stdout();
let mut cnt = 10;
for ch in fp {
if let Ok(b) = ch {
out.write(std::slice::from_ref(&b)).unwrap();
if b == b'n' {
cnt -= 1
}
} else { // Err
cnt -= 1
}
if cnt == 0 {
break
}
}
}
Oxidising the
Command Line
Reading lines
Trait std::io::BufRead
fn read_line(&mut self, buf: &mut String) -> Result<usize>
Read all bytes until a newline (the 0xA byte) is reached, and append them to the provided buffer.
This function will read bytes from the underlying stream until the newline delimiter (the 0xA byte) or EOF is found.
Once found, all bytes up to, and including, the delimiter (if found) will be appended to buf.
If successful, this function will return the total number of bytes read.
If this function returns Ok(0), the stream has reached EOF.
Trait std::io::BufRead
fn lines(self) -> Lines<Self>
Returns an iterator over the lines of this reader.
The iterator returned from this function will yield instances ofio::Result<String>. Each string returned will not
have a newline byte (the 0xA byte) or CRLF (0xD, 0xA bytes) at the end.
Trait std::io::BufRead
fn read_until(&mut self, byte: u8, buf: &mut Vec<u8>) -> Result<usize>
Read all bytes into buf until the delimiter byte or EOF is reached.
This function will read bytes from the underlying stream until the delimiter or EOF is found. Once found, all bytes up
to, and including, the delimiter (if found) will be appended to buf.
If successful, this function will return the total number of bytes read.
use std::io::{stdin, BufRead};
fn main() {
let si = stdin();
let mut stream = si.lock();
let mut line = Vec::new();
let mut linect = 0;
loop {
match stream.read_until(b'n', &mut line) {
Ok(0) => break, // EOF
Ok(_) => linect += 1,
Err(_) => break
}
line.clear()
}
println!("{}", linect);
}
Oxidising the
Command Line
Reading input from stdin or files
void cook_args(char **argv) {
FILE *fp;
fp = stdin;
do {
if (*argv) {
if (!strcmp(*argv, "-"))
fp = stdin;
else if ((fp = fopen(*argv, "r")) == NULL) {
warn("%s", *argv);
rval = 1;
++argv;
continue;
}
}
cook_buf(fp);
if (fp == stdin)
clearerr(fp);
else
(void)fclose(fp);
} while (*argv);
}
Struct std::io::Stdin
impl Read for Stdin
Struct std::fs::File
impl Read for File
use std::io::{stdin, BufRead, BufReader};
let mut fp: Box<BufRead>;
let si = stdin();
let args: Vec<_> = std::env::args().collect();
let mut argv = &args[1..]; // skip the binary name at args[0]
loop {
if argv.is_empty() {
fp = Box::new(si.lock());
} else {
if argv[0] == "-" {
fp = Box::new(si.lock());
} else {
fp = Box::new(BufReader::new(File::open(&argv[0]).unwrap()));
}
argv = &argv[1..];
}
do_something(fp);
if argv.is_empty() {
break
}
}
Oxidising the
Command Line
Handling non-UTF8 arguments
let args: Vec<_> = std::env::args().collect();
% target/debug/cat rutt^I$'266'$'303'k
thread 'main' panicked at 'called `Result::unwrap()` on an `Err` value: "ruttxB6xC3k"',
src/libcore/result.rs:999:5
note: Run with `RUST_BACKTRACE=1` environment variable to display a backtrace.
% echo $?
101
% target/debug/cat rutt^I$'266'$'303'k
thread 'main' panicked at 'called `Result::unwrap()` on an `Err` value: "ruttxB6xC3k"',
src/libcore/result.rs:999:5
note: Run with `RUST_BACKTRACE=1` environment variable to display a backtrace.
% echo $?
101
% env RUST_BACKTRACE=1 target/debug/cat rutt$'266'$'303'k
thread 'main' panicked at 'called `Result::unwrap()` on an `Err` value: "ruttxB6xC3k"',
src/libcore/result.rs:999:5
stack backtrace:
...
14: core::iter::traits::iterator::Iterator::collect
at
/rustc/08bfe16129b0621bc90184f8704523d4929695ef/src/libcore/iter/traits/iterator.rs:1465
15: cat::main
at src/bin/cat.rs:6
...
let args: Vec<_> = std::env::args().collect();
#6 0x000055555556c53a in unwrap<alloc::string::String,std::ffi::os_str::OsString> ()
at /rustc/08bfe16129b0621bc90184f8704523d4929695ef/src/libcore/result.rs:800
800 Err(e) => unwrap_failed("called `Result::unwrap()` on an `Err` value", e),
(gdb) up
#7 {{closure}} () at src/libstd/env.rs:746
746 self.inner.next().map(|s| s.into_string().unwrap())
(gdb) list
741
742 #[stable(feature = "env", since = "1.0.0")]
743 impl Iterator for Args {
744 type Item = String;
745 fn next(&mut self) -> Option<String> {
746 self.inner.next().map(|s| s.into_string().unwrap())
747 }
748 fn size_hint(&self) -> (usize, Option<usize>) { self.inner.size_hint() }
749 }
let argv: Vec<_> = std::env::args_os().collect();
Struct getopts::Matches
pub struct Matches {
pub free: Vec<String>,
// some fields omitted
}
The result of checking command line arguments. Contains a vector of matches and a vector of free strings.
Fields
free: Vec<String>
Free string fragments
Struct clap::ArgMatches
pub fn values_of_os<S: AsRef<str>>(&'a self, name: S) -> Option<OsValues<'a>>
Gets a OsValues struct which is implements Iterator for OsString values of a specific argument. If the option
wasn't present at runtime it returns None. An OS value on Unix-like systems is any series of bytes, regardless of whether
or not they contain valid UTF-8 code points. Since Strings in Rust are guaranteed to be valid UTF-8, a valid filename as
an argument value on Linux (for example) may contain invalid UTF-8 code points.
use clap::{Arg, App};
fn main() {
let matches = App::new("cat")
.arg(Arg::with_name("sflag")
.short("s"))
.arg(Arg::with_name("FILE")
.multiple(true))
.get_matches();
let args: Vec<_> = matches.values_of_os("FILE")
.unwrap()
.collect();
std::process::exit(raw_args(&args));
}
fn raw_args(mut argv: &[&OsStr]) -> i32 {
...
}
Oxidising the
Command Line
Basic toolbox for writing CLI utilities:
Handling Broken Pipes
Reading input by byte
Reading lines
Reading input from stdin or files
Handling non-UTF8 arguments
Questions/Suggestions?
Please contact me at mattpro@yelp.com
We’re Hiring in London!
https://www.yelp.com/careers
Thank you.

More Related Content

PDF
ITGM #9 - Коварный CodeType, или от segfault'а к работающему коду
PDF
[2007 CodeEngn Conference 01] seaofglass - Linux Virus Analysis
PDF
Коварный code type ITGM #9
ODP
CompilersAndLibraries
PPT
为什么 rust-lang 吸引我?
PPT
Евгений Крутько, Многопоточные вычисления, современный подход.
PDF
Php engine
PDF
Алексей Кутумов, Coroutines everywhere
ITGM #9 - Коварный CodeType, или от segfault'а к работающему коду
[2007 CodeEngn Conference 01] seaofglass - Linux Virus Analysis
Коварный code type ITGM #9
CompilersAndLibraries
为什么 rust-lang 吸引我?
Евгений Крутько, Многопоточные вычисления, современный подход.
Php engine
Алексей Кутумов, Coroutines everywhere

What's hot (20)

PDF
One definition rule - что это такое, и как с этим жить
PPT
C tutorial
PDF
PHP Internals and Virtual Machine
PPTX
Vocabulary Types in C++17
PDF
TVM VTA (TSIM)
PDF
[FT-11][suhorng] “Poor Man's” Undergraduate Compilers
PPT
Hooking signals and dumping the callstack
PDF
asyncio internals
PDF
NYU hacknight, april 6, 2016
PDF
Python meetup: coroutines, event loops, and non-blocking I/O
PPTX
C++17 std::filesystem - Overview
PDF
Asterisk: PVS-Studio Takes Up Telephony
PDF
C++ idioms by example (Nov 2008)
PDF
Sniffing Mach Messages
PPT
Csdfsadf
PPTX
Namespaces
PDF
ZeroNights: Automating iOS blackbox security scanning
PDF
Devirtualizing FinSpy
One definition rule - что это такое, и как с этим жить
C tutorial
PHP Internals and Virtual Machine
Vocabulary Types in C++17
TVM VTA (TSIM)
[FT-11][suhorng] “Poor Man's” Undergraduate Compilers
Hooking signals and dumping the callstack
asyncio internals
NYU hacknight, april 6, 2016
Python meetup: coroutines, event loops, and non-blocking I/O
C++17 std::filesystem - Overview
Asterisk: PVS-Studio Takes Up Telephony
C++ idioms by example (Nov 2008)
Sniffing Mach Messages
Csdfsadf
Namespaces
ZeroNights: Automating iOS blackbox security scanning
Devirtualizing FinSpy
Ad

Similar to Rust LDN 24 7 19 Oxidising the Command Line (20)

DOCX
Linux 系統程式--第一章 i/o 函式
PDF
Low Level Exploits
PDF
OS_Compilation_Makefile_kt4jerb34834343553
PPTX
Kernel-Level Programming: Entering Ring Naught
PDF
Writing Rust Command Line Applications
PDF
xv6 is a re−implementation of Dennis Ritchie’s and Ken Thompson’s Unix Versio...
PPTX
Streaming and input output mOOPlec9.pptx
PDF
Play with FILE Structure - Yet Another Binary Exploit Technique
PDF
C言語静的解析ツールと Ruby 1.9 trunk
DOCX
BACKGROUND A shell provides a command-line interface for users. I.docx
PPTX
Object Oriented Programming Using C++: Ch12 Streams and Files.pptx
PPTX
Object Oriented Programming using C++: Ch12 Streams and Files.pptx
PDF
Learning to love the unfamiliar
PPT
File handling(some slides only)
PDF
Interface Oxidation
PDF
Penumbra: Automatically Identifying Failure-Relevant Inputs (ISSTA 2009)
DOCX
Satz1
PPTX
Hypercritical C++ Code Review
PDF
The Ring programming language version 1.10 book - Part 34 of 212
Linux 系統程式--第一章 i/o 函式
Low Level Exploits
OS_Compilation_Makefile_kt4jerb34834343553
Kernel-Level Programming: Entering Ring Naught
Writing Rust Command Line Applications
xv6 is a re−implementation of Dennis Ritchie’s and Ken Thompson’s Unix Versio...
Streaming and input output mOOPlec9.pptx
Play with FILE Structure - Yet Another Binary Exploit Technique
C言語静的解析ツールと Ruby 1.9 trunk
BACKGROUND A shell provides a command-line interface for users. I.docx
Object Oriented Programming Using C++: Ch12 Streams and Files.pptx
Object Oriented Programming using C++: Ch12 Streams and Files.pptx
Learning to love the unfamiliar
File handling(some slides only)
Interface Oxidation
Penumbra: Automatically Identifying Failure-Relevant Inputs (ISSTA 2009)
Satz1
Hypercritical C++ Code Review
The Ring programming language version 1.10 book - Part 34 of 212
Ad

Recently uploaded (20)

PDF
Website Design Services for Small Businesses.pdf
PDF
MCP Security Tutorial - Beginner to Advanced
PDF
Autodesk AutoCAD Crack Free Download 2025
PPTX
Cybersecurity: Protecting the Digital World
PDF
Designing Intelligence for the Shop Floor.pdf
PDF
AI-Powered Threat Modeling: The Future of Cybersecurity by Arun Kumar Elengov...
PPTX
Why Generative AI is the Future of Content, Code & Creativity?
PPTX
Computer Software - Technology and Livelihood Education
PDF
Top 10 Software Development Trends to Watch in 2025 🚀.pdf
PPTX
Log360_SIEM_Solutions Overview PPT_Feb 2020.pptx
PDF
Ableton Live Suite for MacOS Crack Full Download (Latest 2025)
PPTX
WiFi Honeypot Detecscfddssdffsedfseztor.pptx
PPTX
Trending Python Topics for Data Visualization in 2025
PDF
Wondershare Recoverit Full Crack New Version (Latest 2025)
PDF
Microsoft Office 365 Crack Download Free
DOCX
Modern SharePoint Intranet Templates That Boost Employee Engagement in 2025.docx
PPTX
CNN LeNet5 Architecture: Neural Networks
PPTX
Weekly report ppt - harsh dattuprasad patel.pptx
PPTX
Tech Workshop Escape Room Tech Workshop
PDF
The Dynamic Duo Transforming Financial Accounting Systems Through Modern Expe...
Website Design Services for Small Businesses.pdf
MCP Security Tutorial - Beginner to Advanced
Autodesk AutoCAD Crack Free Download 2025
Cybersecurity: Protecting the Digital World
Designing Intelligence for the Shop Floor.pdf
AI-Powered Threat Modeling: The Future of Cybersecurity by Arun Kumar Elengov...
Why Generative AI is the Future of Content, Code & Creativity?
Computer Software - Technology and Livelihood Education
Top 10 Software Development Trends to Watch in 2025 🚀.pdf
Log360_SIEM_Solutions Overview PPT_Feb 2020.pptx
Ableton Live Suite for MacOS Crack Full Download (Latest 2025)
WiFi Honeypot Detecscfddssdffsedfseztor.pptx
Trending Python Topics for Data Visualization in 2025
Wondershare Recoverit Full Crack New Version (Latest 2025)
Microsoft Office 365 Crack Download Free
Modern SharePoint Intranet Templates That Boost Employee Engagement in 2025.docx
CNN LeNet5 Architecture: Neural Networks
Weekly report ppt - harsh dattuprasad patel.pptx
Tech Workshop Escape Room Tech Workshop
The Dynamic Duo Transforming Financial Accounting Systems Through Modern Expe...

Rust LDN 24 7 19 Oxidising the Command Line

  • 1. Oxidising the Command Line July 24. 2019 mattpro@yelp.com
  • 2. Rust at Yelp Yelp connects Users with Great Local Businesses 184 million reviews 35 million unique devices per month Yelp has developed a framework in Rust for real-time A/B testing. It’s used across all Yelp websites and apps, and experiment subjects range from UX to internal infrastructure. Rust was chosen because it’s as fast as C (cheap to run) and safer than C (cheap to maintain). 5,550 employees worldwide
  • 3. Oxidising the Command Line Basic toolbox for writing CLI utilities: Handling Broken Pipes Reading input by byte Reading lines Reading input from stdin or files Handling non-UTF8 arguments
  • 5. fn main() { match std::env::args().nth(1) { Some(y) => loop { println!("{}", y) } None => loop { println!("y") } } }
  • 6. % target/debug/yes | /usr/bin/head y y y y y y y y y y thread 'main' panicked at 'failed printing to stdout: Broken pipe (os error 32)', libstd/io/stdio.rs:700:9 note: Run with `RUST_BACKTRACE=1` environment variable to display a backtrace. % echo "${pipestatus[1]}" 101
  • 7. % /usr/bin/yes | /usr/bin/head y y y y y y y y y y % echo "${pipestatus[1]}" 141
  • 8. #define SIGHUP 1 /* hangup */ #define SIGINT 2 /* interrupt */ #define SIGQUIT 3 /* quit */ #define SIGILL 4 /* illegal instruction (not reset when caught) */ #define SIGTRAP 5 /* trace trap (not reset when caught) */ #define SIGABRT 6 /* abort() */ #define SIGFPE 8 /* floating point exception */ #define SIGKILL 9 /* kill (cannot be caught or ignored) */ #define SIGBUS 10 /* bus error */ #define SIGSEGV 11 /* segmentation violation */ #define SIGSYS 12 /* bad argument to system call */ #define SIGPIPE 13 /* write on a pipe with no one to read it */ #define SIGALRM 14 /* alarm clock */ #define SIGTERM 15 /* software termination signal from kill */ #define SIGURG 16 /* urgent condition on IO channel */ #define SIGSTOP 17 /* sendable stop signal not from tty */ #define SIGTSTP 18 /* stop signal from tty */ #define SIGCONT 19 /* continue a stopped process */ #define SIGCHLD 20 /* to parent on child stop or exit */ ...
  • 9. use std::io::{stdout, Write}; fn main() { let mut out = stdout(); match std::env::args().nth(1) { Some(y) => loop { writeln!(out, "{}", y).unwrap() } None => loop { writeln!(out, "y").unwrap() } } }
  • 10. % target/debug/yes | /usr/bin/head y y y y y y y y y y thread 'main' panicked at 'called `Result::unwrap()` on an `Err` value: Os { code: 32, kind: BrokenPipe, message: "Broken pipe" }', libcore/result.rs:1009:5
  • 11. use std::io::{stdout, ErrorKind::BrokenPipe, Write}; fn main() { let mut out = stdout(); let arg = std::env::args().nth(1); let y = match arg.as_ref() { Some(a) => a, None => "y", }; loop { if let Err(e) = writeln!(out, "{}", y) { if e.kind() == BrokenPipe { std::process::exit(141) } else { panic!("{:?}", e) } } } }
  • 12. % target/debug/yes | /usr/bin/head y y y y y y y y y y % echo "${pipestatus[1]}" 141
  • 14. Trait std::io::Read fn bytes(self) -> Bytes<Self> Transforms this Read instance to an Iterator over its bytes. The returned type implements Iterator where the Item is Result<u8,io::Error>. The yielded item is Ok if a byte was successfully read and Err otherwise. EOF is mapped to returning None from this iterator.
  • 15. use std::io::{stdin, stdout, Read, Write}; fn main() { let fp = stdin().bytes(); let mut out = stdout(); let mut cnt = 10; for ch in fp { if let Ok(b) = ch { out.write(b).unwrap(); if b == b'n' { cnt -= 1 } } else { // Err cnt -= 1 } if cnt == 0 { break } } }
  • 16. error[E0308]: mismatched types --> src/bin/head.rs:13:23 | 13 | out.write(b).unwrap(); | ^ expected &[u8], found u8 | = note: expected type `&[u8]` found type `u8`
  • 17. Trait std::io::Write fn write(&mut self, buf: &[u8]) -> Result<usize>
  • 18. Module std::slice pub fn from_ref<T>(s: &T) -> &[T] Converts a reference to T into a slice of length 1 (without copying).
  • 19. use std::io::{stdin, stdout, Read, Write}; fn main() { let fp = stdin().bytes(); let mut out = stdout(); let mut cnt = 10; for ch in fp { if let Ok(b) = ch { out.write(std::slice::from_ref(&b)).unwrap(); if b == b'n' { cnt -= 1 } } else { // Err cnt -= 1 } if cnt == 0 { break } } }
  • 21. Trait std::io::BufRead fn read_line(&mut self, buf: &mut String) -> Result<usize> Read all bytes until a newline (the 0xA byte) is reached, and append them to the provided buffer. This function will read bytes from the underlying stream until the newline delimiter (the 0xA byte) or EOF is found. Once found, all bytes up to, and including, the delimiter (if found) will be appended to buf. If successful, this function will return the total number of bytes read. If this function returns Ok(0), the stream has reached EOF.
  • 22. Trait std::io::BufRead fn lines(self) -> Lines<Self> Returns an iterator over the lines of this reader. The iterator returned from this function will yield instances ofio::Result<String>. Each string returned will not have a newline byte (the 0xA byte) or CRLF (0xD, 0xA bytes) at the end.
  • 23. Trait std::io::BufRead fn read_until(&mut self, byte: u8, buf: &mut Vec<u8>) -> Result<usize> Read all bytes into buf until the delimiter byte or EOF is reached. This function will read bytes from the underlying stream until the delimiter or EOF is found. Once found, all bytes up to, and including, the delimiter (if found) will be appended to buf. If successful, this function will return the total number of bytes read.
  • 24. use std::io::{stdin, BufRead}; fn main() { let si = stdin(); let mut stream = si.lock(); let mut line = Vec::new(); let mut linect = 0; loop { match stream.read_until(b'n', &mut line) { Ok(0) => break, // EOF Ok(_) => linect += 1, Err(_) => break } line.clear() } println!("{}", linect); }
  • 25. Oxidising the Command Line Reading input from stdin or files
  • 26. void cook_args(char **argv) { FILE *fp; fp = stdin; do { if (*argv) { if (!strcmp(*argv, "-")) fp = stdin; else if ((fp = fopen(*argv, "r")) == NULL) { warn("%s", *argv); rval = 1; ++argv; continue; } } cook_buf(fp); if (fp == stdin) clearerr(fp); else (void)fclose(fp); } while (*argv); }
  • 27. Struct std::io::Stdin impl Read for Stdin Struct std::fs::File impl Read for File
  • 28. use std::io::{stdin, BufRead, BufReader}; let mut fp: Box<BufRead>; let si = stdin(); let args: Vec<_> = std::env::args().collect(); let mut argv = &args[1..]; // skip the binary name at args[0] loop { if argv.is_empty() { fp = Box::new(si.lock()); } else { if argv[0] == "-" { fp = Box::new(si.lock()); } else { fp = Box::new(BufReader::new(File::open(&argv[0]).unwrap())); } argv = &argv[1..]; } do_something(fp); if argv.is_empty() { break } }
  • 30. let args: Vec<_> = std::env::args().collect();
  • 31. % target/debug/cat rutt^I$'266'$'303'k thread 'main' panicked at 'called `Result::unwrap()` on an `Err` value: "ruttxB6xC3k"', src/libcore/result.rs:999:5 note: Run with `RUST_BACKTRACE=1` environment variable to display a backtrace. % echo $? 101
  • 32. % target/debug/cat rutt^I$'266'$'303'k thread 'main' panicked at 'called `Result::unwrap()` on an `Err` value: "ruttxB6xC3k"', src/libcore/result.rs:999:5 note: Run with `RUST_BACKTRACE=1` environment variable to display a backtrace. % echo $? 101 % env RUST_BACKTRACE=1 target/debug/cat rutt$'266'$'303'k thread 'main' panicked at 'called `Result::unwrap()` on an `Err` value: "ruttxB6xC3k"', src/libcore/result.rs:999:5 stack backtrace: ... 14: core::iter::traits::iterator::Iterator::collect at /rustc/08bfe16129b0621bc90184f8704523d4929695ef/src/libcore/iter/traits/iterator.rs:1465 15: cat::main at src/bin/cat.rs:6 ...
  • 33. let args: Vec<_> = std::env::args().collect();
  • 34. #6 0x000055555556c53a in unwrap<alloc::string::String,std::ffi::os_str::OsString> () at /rustc/08bfe16129b0621bc90184f8704523d4929695ef/src/libcore/result.rs:800 800 Err(e) => unwrap_failed("called `Result::unwrap()` on an `Err` value", e), (gdb) up #7 {{closure}} () at src/libstd/env.rs:746 746 self.inner.next().map(|s| s.into_string().unwrap()) (gdb) list 741 742 #[stable(feature = "env", since = "1.0.0")] 743 impl Iterator for Args { 744 type Item = String; 745 fn next(&mut self) -> Option<String> { 746 self.inner.next().map(|s| s.into_string().unwrap()) 747 } 748 fn size_hint(&self) -> (usize, Option<usize>) { self.inner.size_hint() } 749 }
  • 35. let argv: Vec<_> = std::env::args_os().collect();
  • 36. Struct getopts::Matches pub struct Matches { pub free: Vec<String>, // some fields omitted } The result of checking command line arguments. Contains a vector of matches and a vector of free strings. Fields free: Vec<String> Free string fragments
  • 37. Struct clap::ArgMatches pub fn values_of_os<S: AsRef<str>>(&'a self, name: S) -> Option<OsValues<'a>> Gets a OsValues struct which is implements Iterator for OsString values of a specific argument. If the option wasn't present at runtime it returns None. An OS value on Unix-like systems is any series of bytes, regardless of whether or not they contain valid UTF-8 code points. Since Strings in Rust are guaranteed to be valid UTF-8, a valid filename as an argument value on Linux (for example) may contain invalid UTF-8 code points.
  • 38. use clap::{Arg, App}; fn main() { let matches = App::new("cat") .arg(Arg::with_name("sflag") .short("s")) .arg(Arg::with_name("FILE") .multiple(true)) .get_matches(); let args: Vec<_> = matches.values_of_os("FILE") .unwrap() .collect(); std::process::exit(raw_args(&args)); } fn raw_args(mut argv: &[&OsStr]) -> i32 { ... }
  • 39. Oxidising the Command Line Basic toolbox for writing CLI utilities: Handling Broken Pipes Reading input by byte Reading lines Reading input from stdin or files Handling non-UTF8 arguments
  • 41. We’re Hiring in London! https://www.yelp.com/careers