Run a Directory of Scripts Predictably with run-parts
By the end of this guide, you will have a small directory of executable scripts that run-parts can preview, run in a known order, and pass arguments to. The examples use the Debian debianutils implementation, version 5.17 on the machine used for this guide.
The route
Jump straight to the step you need, or tick off Done means at the end.
Allow about 10 minutes. You need a shell, run-parts, and permission to create files in a temporary directory. The examples do not need elevated privileges. Do not test against /etc until you have inspected exactly what will run: a directory may contain scripts that change system state.
1. Confirm the installed implementation
Check both the package and the command before relying on its details:
$ dpkg-query -W -f='${Package} ${Version}\n' debianutils
debianutils 5.17build1
$ run-parts --version
Debian run-parts program, version 5.17
Checkpoint: the exact package revision can differ between Debian releases, but the command should identify itself as Debian run-parts. The rest of this guide follows the installed run-parts(8) contract.
2. Build a harmless test directory
Make two executable scripts and one file that should be ignored. The allowed default filename characters are ASCII letters, digits, underscores, and hyphens. A filename containing a dot is not selected by the default rules.
$ WORK_DIR=$(mktemp -d)
$ mkdir "$WORK_DIR/jobs"
$ printf '%s\n' '#!/bin/sh' 'printf "first: %s\\n" "$1"' > "$WORK_DIR/jobs/10_first"
$ printf '%s\n' '#!/bin/sh' 'printf "second: %s\\n" "$1"' > "$WORK_DIR/jobs/20_second"
$ printf '%s\n' '#!/bin/sh' 'printf "ignored\\n"' > "$WORK_DIR/jobs/30_second.sh"
$ chmod 755 "$WORK_DIR/jobs/10_first" "$WORK_DIR/jobs/20_second"
$ chmod 644 "$WORK_DIR/jobs/30_second.sh"
The scripts are executable, while 30_second.sh is deliberately not. Keep WORK_DIR in your shell for the later steps. When finished, remove this temporary directory with rm -rf -- "$WORK_DIR"; that command is destructive, so check the variable with printf '%s\n' "$WORK_DIR" first.
3. Preview selection before running anything
Use --test to print executable names that would run. It makes no changes and does not execute the scripts:
$ run-parts --test "$WORK_DIR/jobs"
run-parts: executing /tmp/tmp.example/jobs/10_first morning
/tmp/tmp.example/jobs/20_second
Your temporary path will differ. The important result is that the two executable files appear and 30_second.sh does not. For a directory where you need to see matching non-executable files as well, use --list instead. --list and --test cannot be combined.
Checkpoint: if nothing is listed, inspect the directory with ls -la "$WORK_DIR/jobs". The usual causes are missing execute permission, a dot in the filename, or pointing at the wrong directory.
4. Run in lexical order and pass an argument
Without extra options, matching files run sequentially in C/POSIX lexical order. Use --verbose when you want the name printed before each script. Repeat --arg for each argument:
$ run-parts --verbose --arg=morning "$WORK_DIR/jobs"
/tmp/tmp.example/jobs/10_first
first: morning
run-parts: executing /tmp/tmp.example/jobs/20_second morning
second: morning
The verbose lines are written to standard error; the script output is separate. Prefixes such as 10_ and 20_ make the intended order visible. Do not rely on directory creation order.
To reverse the same order, add --reverse. This is still sequential execution, just with the lexical order inverted:
$ run-parts --reverse --arg=evening "$WORK_DIR/jobs"
second: evening
first: evening
5. Choose names with a deliberate rule
The default filter is intentionally narrow. If you need names with dots, select them with an extended regular expression and preview first:
$ run-parts --list --regex='^30_.*\.sh$' "$WORK_DIR/jobs"
/tmp/tmp.example/jobs/30_second.sh
--list reports matching files whether they are executable, so this command proves the pattern but does not prove that the file can run. If you want it executed, make it executable and repeat the preview with --test --regex='^30_.*\.sh$'.
--lsbsysinit is another filename policy. It accepts the LSB, LANANA, and Debian cron namespaces and rejects names ending in .dpkg-old, .dpkg-dist, .dpkg-new, or .dpkg-tmp. Use one explicit policy rather than assuming that a filename accepted by another scheduler will also be accepted here.
6. Decide how failures should propagate
By default, run-parts continues after a script returns a non-zero status. That can be useful for independent jobs, but it can also hide a failed prerequisite. Add --exit-on-error when later scripts must not run after the first failure.
$ run-parts --exit-on-error "$WORK_DIR/jobs"
first:
second:
$ printf 'run-parts status: %s\n' "$?"
run-parts status: 0
For a real failure test, put a script that exits non-zero first in lexical order, then confirm that its status stops the run. Do not add a failing test script to a production directory: run-parts executes every selected executable.
Use --report when you want names only for scripts that produce output. Use --debug when selection itself is confusing; it reports which scripts are selected and which are not.
7. Understand the safety boundaries
The command sets a default umask of 022 before running scripts. Override it with an octal value such as --umask=077 when child-created files must be private. Treat this as a property of the run, not a replacement for checking what each script does.
--new-session starts each script in a separate process session. With it, killing run-parts does not kill the currently running script; that script continues until completion. This can matter during an emergency stop, so do not add it casually to jobs that must stop together.
Use -- to end options when a directory argument could begin with a hyphen. Keep scripts idempotent where possible, log their meaningful actions, and preview a changed directory before the next scheduled run. There is no rollback built into run-parts; recovery belongs to the scripts and the state they change.
Done means
run-parts --versionidentifies the installed Debian implementation.--testshows exactly the executable files selected before execution.- Script names and lexical order match your intended workflow.
- Arguments, umask, output reporting, and failure handling are explicit.
- You have removed the temporary directory after checking its path.