Skip to content

Commit b6e7ba5

Browse files
committed
feat(builtins): implement find -exec command execution
Closes #320. The find builtin's -exec flag was parsed but acted like -print because the builtin lacked interpreter access. Now find -exec is intercepted at the interpreter level (like xargs/timeout) so commands are executed via the interpreter for each matched path. Supports both per-file (-exec cmd {} \;) and batch (-exec cmd {} +) modes with {} placeholder substitution. https://claude.ai/code/session_01QbjrsMFJbHy5XfHCzA6TjM
1 parent ef0c02d commit b6e7ba5

File tree

3 files changed

+467
-13
lines changed

3 files changed

+467
-13
lines changed

crates/bashkit/src/builtins/ls.rs

Lines changed: 10 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -295,20 +295,19 @@ struct FindOptions {
295295
name_pattern: Option<String>,
296296
type_filter: Option<char>,
297297
max_depth: Option<usize>,
298-
// -exec is parsed but acts like -print (builtin can't invoke interpreter)
299-
// WTF: exec needs interpreter access; for now just collect paths so scripts don't error
300-
has_exec: bool,
301298
}
302299

303300
/// The find builtin - search for files.
304301
///
305-
/// Usage: find [PATH...] [-name PATTERN] [-type TYPE] [-maxdepth N]
302+
/// Usage: find [PATH...] [-name PATTERN] [-type TYPE] [-maxdepth N] [-exec CMD {} \;]
306303
///
307304
/// Options:
308-
/// -name PATTERN Match filename against PATTERN (supports * and ?)
309-
/// -type TYPE Match file type: f (file), d (directory), l (link)
310-
/// -maxdepth N Descend at most N levels
311-
/// -print Print matching paths (default)
305+
/// -name PATTERN Match filename against PATTERN (supports * and ?)
306+
/// -type TYPE Match file type: f (file), d (directory), l (link)
307+
/// -maxdepth N Descend at most N levels
308+
/// -print Print matching paths (default)
309+
/// -exec CMD {} \; Execute CMD for each match ({} = path)
310+
/// -exec CMD {} + Execute CMD once with all matches
312311
pub struct Find;
313312

314313
#[async_trait]
@@ -319,7 +318,6 @@ impl Builtin for Find {
319318
name_pattern: None,
320319
type_filter: None,
321320
max_depth: None,
322-
has_exec: false,
323321
};
324322

325323
// Parse arguments
@@ -375,9 +373,8 @@ impl Builtin for Find {
375373
// Default action, ignore
376374
}
377375
"-exec" | "-execdir" => {
378-
// Parse -exec command {} \; or {} +
379-
// Skip all args until we find \; or +
380-
opts.has_exec = true;
376+
// -exec is handled at interpreter level (execute_find);
377+
// skip args here for fallback path
381378
i += 1;
382379
while i < ctx.args.len() {
383380
let a = &ctx.args[i];
@@ -501,7 +498,7 @@ fn find_recursive<'a>(
501498
}
502499

503500
/// Simple glob pattern matching for find -name
504-
fn glob_match(value: &str, pattern: &str) -> bool {
501+
pub(crate) fn glob_match(value: &str, pattern: &str) -> bool {
505502
let mut value_chars = value.chars().peekable();
506503
let mut pattern_chars = pattern.chars().peekable();
507504

crates/bashkit/src/builtins/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,7 @@ pub use headtail::{Head, Tail};
9999
pub use hextools::{Hexdump, Od, Xxd};
100100
pub use inspect::{File, Less, Stat};
101101
pub use jq::Jq;
102+
pub(crate) use ls::glob_match;
102103
pub use ls::{Find, Ls, Rmdir};
103104
pub use navigation::{Cd, Pwd};
104105
pub use nl::Nl;

0 commit comments

Comments
 (0)