TIL: How to track down a shell configuration option (alias, variable, etc.)

Shell, TIL

September 07, 2022

Sometimes you find that you have an alias defined in your shell, or an environment variable that you set. However, you’re not entirely sure where it’s defined. Here’s how you can figure that out.

Today I discovered this one-liner:

PS4='+%x:%I>' zsh -ixc '' |& grep expr

Let’s break this down.

The first thing that’s set is PS4. PS4 is the prompt that’s displayed before an execution trace (i.e. the output shown when you do set -x). The PS4 string +%x:%I> means to print + (replicated automatically to show multiple levels of indirection), followed by the filename (%x), the line number in that file (%I), and a > character.

Then we start the shell; in my case, zsh, but this works with bash too. The -i option means to start an interactive shell (because we want it in the exact same state as an interactive session), -x means to show the commands being executed (prefixed with the PS4 we set before), and -c means to run a command and exit (in this case, we use '' to not run any commands).

That’s already the most important part: at this point, we have a full trace of the code executed on shell startup.

To find the line we’re looking for, we pipe it to grep with the |& shorthand, which just translates to 2>&1 | (the execution trace is on standard error), and use grep to search for expr. But this redirection allows us to do even more complex things: for example, we can get a deduplicated list of all the files sourced by the shell at startup, in the order they’re sourced:

PS4="+%x>" zsh -ixc '' |& awk -F'>' '!a[$1]++ { print $1 }'

That bit of AWK magic deserves its own post, but basically it’s a way to get unique lines of text without the need to sort them. Normally you could pipe to | sort | uniq or just | sort -u, but in this case we want to also see the order in which files are sourced, so AWK is the best choice.