Bash Command Resolution Trace
ct (Command Trace) is a Bash command resolution tracer.
It examines how a command name resolves and traces the subsequent filesystem and execution layers, bringing them together into a single resolution model.
The goal is to answer not only what command Bash will use, but why it resolves that way and what ultimately executes.
When Bash encounters a command name, it does not simply search $PATH.
Depending on the command and the current shell environment, Bash may resolve the name as:
- an alias
- a function
- a reserved keyword
- a builtin
- an external executable found through
$PATH
The resolution can also be affected by POSIX mode, disabled builtins, and $PATH ordering.
When an external executable is selected, additional filesystem and execution layers can affect what ultimately runs, including symlinks, /etc/alternatives, interpreter paths, and system directory layouts.
Traditional tools such as type, which, and command -v answer useful but much narrower questions.
ct is intended to answer the broader question:
Why does this command resolve the way it does?
For a command such as:
ct awkct can show:
- aliases
- functions
- reserved keywords
- builtin status
- disabled builtins
- external executables
$PATHentries in search order- shadowed executables
- canonical filesystem paths
- symlink chains
/etc/alternativesindirection/usr-merge relationships- ELF interpreters
- script shebangs
- the Bash resolution target
- the kernel execution target, when applicable
This makes ct useful when a command behaves differently from what was expected.
The Bash resolution target and the kernel execution target are not necessarily the same thing
For an ELF executable, the path Bash resolves may pass through filesystem indirection before the kernel loads the executable and its ELF interpreter:
Bash Resolution Target
↓
/usr/bin/example
↓
symlink
↓
/usr/bin/example-real
↓
ELF interpreter
↓
kernel execution
For scripts, the execution path can instead involve a shebang:
Bash Resolution Target
↓
/usr/local/bin/example
↓
#!/usr/bin/env python3
↓
interpreter
↓
kernel execution
ct exposes these layers as a whole snapshot of command resolution.
ct examines $PATH in order and identifies how those entries affect command visibility.
This includes:
- the first executable Bash can reach
- later shadowed executables
- duplicate or equivalent filesystem locations
- system directories that are not currently present in
$PATH
This is particularly useful when multiple versions of a command exist.
For example:
ct pythoncan show not only which python is selected, but what other candidates exist behind it.
Some system commands exist in administrative directories such as:
/usr/sbin
/sbin
These directories may not be present in an ordinary user's $PATH.
ct can temporarily extend the search path for discovery, allowing it to determine whether an otherwise hidden command exists outside the current $PATH.
The shell environment is restored afterward.
Manual extension is useful when investigating command-name conflicts involving directories that are not currently in $PATH.
For example, if a user command shadows a system command, extending $PATH can expose the system copy and show the resulting shadowing relationship:
ct -x useraddThis is particularly useful for determining whether a command in a user-controlled directory is masking an administrative or system command.
ct -c is a separate analysis mode for finding command-name collisions inside the current Bash environment.
ct -cIt examines command names provided by:
- aliases
- functions
- builtins
- reserved keywords
and checks whether those names also exist as external commands.
This answers a different question from normal command tracing:
Which names in this shell environment can represent more than one kind of command?
A normal resolution trace is concerned with how one particular command resolves.
Conflict analysis is concerned with potential collisions across the environment.
ct -c therefore does not perform a complete $PATH trace for every collision. External commands are used as presence indicators rather than producing a full resolution report.
This keeps conflict reports focused instead of filling them with normal $PATH precedence information.
ct can emit machine-readable JSON:
ct -j awkJSON mode is intended for:
- scripting
- automation
- inspection
- integration with other tools
Conflict analysis can also produce JSON:
ct -c -jBoolean values are emitted as JSON booleans, and null is used where a field is not applicable.
The JSON structure may evolve between major versions.
- Bash command resolution tracing
- Alias, function, keyword, builtin, and executable detection
- Enabled and disabled builtin detection
$PATHvisibility and precedence analysis- Shadowed command detection
- Filesystem and symlink resolution
/etc/alternativesdetection/usr-merge detection- ELF interpreter and shebang detection
- Bash resolution target and kernel execution target analysis
- Automatic
$PATHextension for discovery - Manual
$PATHextension with-x - Environment conflict analysis with
-c - JSON output with
-j - Combined short options such as
-cjx - Colorized human-readable output
- Tab completion
- Shell environment preservation
- Interactive-shell and script usage
Clone the repository:
git clone https://github.com/JB63134/bash_ct.git /usr/local/bin/bash_ctSource .bash_ct from your Bash startup file:
echo "source /usr/local/bin/bash_ct/.bash_ct" >> ~/.bashrcThen reload the shell:
source ~/.bashrc- Bash 4.4 or newer
ct requires:
readlinkreadelfmktempstat
tput is used for color output when available.
ct [options] command
| Option | Description |
|---|---|
-h, --help |
Show usage information |
-v, --version |
Show version and license |
-j, --json |
Emit JSON output |
-x, --extend |
Extend $PATH for discovery |
-c, --conflict |
Environment conflict analysis |
Combined short options are supported:
ct -cjxTrace an external command:
ct lsTrace a command with potentially interesting filesystem resolution:
ct pythonProduce JSON:
ct -j bashDiscover commands outside the normal $PATH:
ct -x useraddAnalyze command-name conflicts:
ct -cCombine options:
ct -cjxct operates on bare command names.
Valid:
ct awk
ct python
ct cdNot valid:
ct /bin/ls
ct ./scriptThis restriction reflects what ct is designed to investigate: Bash command-name resolution, rather than arbitrary pathname execution.
A command can look simple at the prompt:
$ foobut Bash may have several layers of information to consider when resolving it.
There may be:
aliases
functions
builtins / keywords
$PATH executables
shadowed entries
symlink chains
ELF interpreters or shebangs
Most command-discovery tools expose only a portion of this information.
ct was built to make these layers inspectable.
The goal is not merely to answer:
Where is
foo?
but:
What does
foomean in this Bash environment, what is hiding behind it, what else could it resolve to, and, when applicable, what will actually execute?





