forked from dathere/qsv
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathforeach.rs
102 lines (79 loc) · 2.89 KB
/
foreach.rs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
use csv;
use regex::bytes::Regex;
use std::process::{Command, Stdio};
use std::io::{BufReader, BufRead};
use std::ffi::OsStr;
use std::os::unix::ffi::OsStrExt;
use CliResult;
use config::{Delimiter, Config};
use select::SelectColumns;
use util;
static USAGE: &'static str = "
Execute a bash command once per line in given CSV file.
Usage:
xsv foreach [options] <column> <command> [<input>]
foreach options:
-u, --unify If the output of execute command is CSV, will
unify the result by skipping headers on each
subsequent command.
-c, --new-column If --unify is set, add a new column with given name
and copying the value of the current input file line.
Common options:
-h, --help Display this message
-n, --no-headers When set, the file will be considered to have no
headers.
-d, --delimiter <arg> The field delimiter for reading CSV data.
Must be a single character. (default: ,)
";
#[derive(Deserialize)]
struct Args {
arg_column: SelectColumns,
arg_command: String,
arg_input: Option<String>,
flag_unify: bool,
flag_new_column: Option<String>,
flag_no_headers: bool,
flag_delimiter: Option<Delimiter>,
}
pub fn run(argv: &[&str]) -> CliResult<()> {
let args: Args = util::get_args(USAGE, argv)?;
let rconfig = Config::new(&args.arg_input)
.delimiter(args.flag_delimiter)
.no_headers(args.flag_no_headers)
.select(args.arg_column);
let mut rdr = rconfig.reader()?;
let template_pattern = Regex::new(r"\{\}")?;
let headers = rdr.byte_headers()?.clone();
let sel = rconfig.selection(&headers)?;
let column_index = *sel.iter().next().unwrap();
let mut record = csv::ByteRecord::new();
let space: u8 = 32;
while rdr.read_byte_record(&mut record)? {
let templated_command = template_pattern
.replace_all(&args.arg_command.as_bytes(), &record[column_index])
.to_vec();
let mut command_pieces = templated_command.split(|char| *char == space);
let prog = command_pieces.next().unwrap();
let mut args = Vec::new();
for piece in command_pieces {
args.push(OsStr::from_bytes(piece));
}
println!("{:?}", args);
let mut cmd = Command::new(OsStr::from_bytes(prog))
.args(args)
.stdout(Stdio::inherit())
.stderr(Stdio::inherit())
.spawn()
.unwrap();
// {
// let stdout = cmd.stdout.as_mut().unwrap();
// let stdout_reader = BufReader::new(stdout);
// let stdout_lines = stdout_reader.lines();
// for line in stdout_lines {
// println!("{}", line?);
// }
// }
cmd.wait().unwrap();
}
Ok(())
}