Jesse Rosenstock 5269e233a6 find: implement -ok and -okdir (#650)
-ok is like -exec ... ; but prompts the user on stderr before each
invocation and only runs the command if the response is affirmative
(starts with 'y' or 'Y').  -okdir is the corresponding -execdir variant.
Only the ';' terminator is accepted: POSIX does not define -ok ... + and
GNU find rejects it.

Response source: GNU find reads from /dev/tty so that the user's answer
always comes from the real terminal even when stdin is occupied (e.g.
`find -files0-from - -ok rm {} \;` reads paths from stdin, so responses
cannot also come from there).  /dev/tty is the POSIX name for a
process's controlling terminal and exists on all Unix-like systems.  We
open /dev/tty only when stdin is itself a terminal
(std::io::stdin().is_terminal() == true).  When stdin is a pipe or file,
we read from stdin directly — matching BSD find and making scripted use
(and integration tests via pipe_in()) work naturally without any special
environment variable.  On Windows, or when /dev/tty cannot be opened, we
likewise fall back to stdin.

Implementation: rather than a separate OkMatcher that duplicated
SingleExecMatcher's fields, constructor, and exec logic, the interactive
prompt is folded into SingleExecMatcher behind an `interactive: bool`
field.  `SingleExecMatcher::new_interactive()` constructs the -ok/-okdir
variant; `matches()` adds a guarded block that builds a GNU-find-style
prompt ("< executable arg... >? ") and calls `matcher_io.confirm()`
before executing.  If the user declines, the expression is false and the
command is not run.  This keeps the arg-parsing, path resolution,
current_dir logic, and error handling in one place so bug fixes apply to
both -exec and -ok.

Dependencies::confirm() trait method: abstracts prompt+read so matchers
remain testable without a real terminal; FakeDependencies uses a
VecDeque of preset responses.

Tests:
- Unit tests (exec_unit_tests.rs): confirmed executes command, declined
  skips command and returns false, confirmed but command fails returns
  false, -okdir runs in parent dir
- Parser unit tests (matchers/mod.rs): missing-arg errors, missing
  semicolon, correct parse, confirm/decline via FakeDependencies
- Integration tests (test_find.rs): pipe_in() makes stdin a pipe so
  is_terminal() returns false and responses are read from the pipe;
  "y"/"Y"/"yes"/" y" run command, "n" and empty response skip command,
  -okdir runs in parent dir, prompt format verified, missing-semicolon
  error

Closes https://github.com/uutils/findutils/issues/8.
2026-06-04 20:31:54 +02:00
2026-06-04 20:31:54 +02:00
2026-04-08 16:40:31 +02:00
2023-08-19 19:34:30 +02:00
2017-03-08 14:39:37 +00:00
2025-05-05 09:15:45 -07:00
2026-05-05 09:02:14 +02:00

findutils

Crates.io Discord License dependency status codecov

Rust implementation of GNU findutils: xargs, find, locate and updatedb. The goal is to be a full drop-in replacement of the original commands.

Run the GNU testsuite on rust/findutils:

bash util/build-gnu.sh

# To run a specific test:
bash util/build-gnu.sh tests/misc/help-version.sh

Comparing with GNU

Evolution over time - GNU testsuite Evolution over time - BFS testsuite

Build/run with BFS

bfs is a variant of the UNIX find command that operates breadth-first rather than depth-first.

bash util/build-bfs.sh

# To run a specific test:
bash util/build-bfs.sh posix/basic

For more details, see https://github.com/uutils/findutils-tracking/

S
Description
No description provided
Readme MIT 2.7 MiB
Languages
Rust 98.7%
Shell 1%
Python 0.3%