rg (ripgrep 15.2), grep (ours, on ripgrep's regex crates), find and xargs (ours), sed (uutils 0.3 wrapper), diff and cmp (uutils diffutils 0.6 with -r), fd 10.5, jaq 2.3, env and timeout. userland/spawn is a small Command-like client of the process interface. search-test.nu: 42 cases match native tools.
40 lines
1.8 KiB
Rust
40 lines
1.8 KiB
Rust
//! Build sequential child commands from quoted or NUL-delimited input.
|
|
use std::io::{self, Read};
|
|
use sausage_spawn::{Command, Stdio};
|
|
fn run() -> Result<i32, Box<dyn std::error::Error>> {
|
|
let args: Vec<_> = std::env::args().skip(1).collect();
|
|
let mut i = 0;
|
|
let mut count = usize::MAX;
|
|
let mut null = false;
|
|
let mut no_empty = false;
|
|
while i < args.len() {
|
|
match args[i].as_str() {
|
|
"-0" => null = true,
|
|
"-r" => no_empty = true,
|
|
"-n" => { i += 1; count = args.get(i).ok_or("missing -n argument")?.parse()?; }
|
|
"--" => { i += 1; break; }
|
|
arg if arg.starts_with("-n") => count = arg[2..].parse()?,
|
|
arg if arg.starts_with('-') => return Err(format!("unsupported option: {arg}").into()),
|
|
_ => break,
|
|
}
|
|
i += 1;
|
|
}
|
|
if count == 0 { return Err("-n must be positive".into()); }
|
|
let argv = if i == args.len() { vec!["echo".into()] } else { args[i..].to_vec() };
|
|
let mut input = String::new(); io::stdin().read_to_string(&mut input)?;
|
|
let values = if null { input.split_terminator('\0').map(str::to_owned).collect() }
|
|
else { shlex::split(&input).ok_or("unmatched quote in input")? };
|
|
if values.is_empty() && no_empty { return Ok(0); }
|
|
let mut result = 0;
|
|
let batches = if values.is_empty() { vec![&[][..]] } else { values.chunks(count).collect() };
|
|
for batch in batches {
|
|
match Command::new(&argv[0]).args(&argv[1..]).args(batch).stdin(Stdio::Null).status() {
|
|
Ok(0) => (), Ok(255) => return Ok(124), Ok(_) => result = 123,
|
|
Err(e) if e.kind() == io::ErrorKind::NotFound => return Ok(127),
|
|
Err(_) => return Ok(126),
|
|
}
|
|
}
|
|
Ok(result)
|
|
}
|
|
fn main() { std::process::exit(match run() { Ok(code) => code, Err(e) => { eprintln!("xargs: {e}"); 1 } }); }
|