run-one is a Linux C rewrite of Dustin Kirkland's original
run-one shell utility. It keeps
the original command-line API while replacing the shell implementation and its
runtime helper programs with a small native executable.
The six public entry points are:
run-one COMMAND [ARG ...]runs one instance for a command/argument identity.run-this-one COMMAND [ARG ...]terminates matching instances before running this one.run-one-constantly COMMAND [ARG ...]respawns after every exit.keep-one-running COMMAND [ARG ...]aliasesrun-one-constantly.run-one-until-success COMMAND [ARG ...]respawns until status 0.run-one-until-failure COMMAND [ARG ...]respawns until a non-zero status.
There are no wrapper options before COMMAND; this is part of the compatibility
contract. A command named -- or beginning with - is still a command.
The original utility is small and commonly used from unattended jobs, where a subtle compatibility regression can remain hidden for a long time. This rewrite therefore treats the shell implementation as the compatibility oracle for the public interface and lock namespace, while making execution, supervision, and replacement explicit and testable.
The executable has no runtime dependency on the original sha512sum, awk,
flock, pgrep, kill, lsof, logger, mktemp, or sleep command chain.
SHA-512 is provided by OpenSSL libcrypto; locking and process operations use
Linux/POSIX interfaces directly.
The rewrite preserves the six command names, argument-only CLI, normal
SHA-512 lock namespace, cache-location policy, non-blocking lock behavior,
restart policy, command status propagation, and inherited lock descriptor.
Legacy flock(1) locks and the C rewrite contend on the same lock file for
normal command strings.
A few shell implementation accidents are deliberately not preserved:
run-this-onecompares Linux process argument vectors literally instead of interpreting the joined command text as a regular expression.- SHA-512 input is deterministic for
echoedge cases such as-nand backslash-containing arguments. - Lock files are opened without following a final symlink where
O_NOFOLLOWis available, and newly created lock files use mode0600.
The historical space-joined lock identity remains intentionally ambiguous: argument vectors that produce the same space-joined text still contend on the same lock.
See run-one(1) for the complete behavioral contract and exit-status rules.
Requirements:
- Linux
- a C11-capable compiler with GNU extensions
- Meson 1.4.0 or newer
- Ninja
pkg-config- OpenSSL
libcrypto1.1.1 or newer scdoc
Build and test with:
meson setup build
meson compile -C build
meson test -C build --print-errorlogsInstall with:
meson install -C buildUse --prefix, --bindir, --mandir, and DESTDIR through the standard Meson
interfaces when packaging.
The regression suite is intentionally larger than the program. It covers all
six public invocation names, representative normal and signal exits, failed
execution, cache selection, SHA-512 compatibility, lock contention and races,
legacy flock(1) interoperability, inherited-lock lifetime, restart policies,
replacement of zero/one/multiple processes, script/interpreter behavior, exact
argument matching, long argument vectors, and compatibility-sensitive edge
cases.
Copyright (C) 2026 Alexandr Savca alexandr.savca89@gmail.com.
This C rewrite is licensed under the GNU General Public License, version 3 or
(at your option) any later version. See COPYING.
The original run-one program and public interface were written by Dustin
Kirkland. This repository is an independent rewrite and does not claim
authorship of the original utility.