Shell pipes and readline completion
On what seemed random occasions, readline
completion would break in my
terminal (e.g., when trying to use pdb
after setting a Python breakpoint()
),
just to restart working later on.
I originally thought about my TERM
variables being misconfigured, the use of
direnv
, and so on. But it was none of that.
On a closer look, it only happened when running make extract
to process
Beancount transactions from bank statements and financial documents. Why?
The Makefile extract
target looks as follows:
extract:
$(RUN) bean-extract -f $(INDEX).beancount -e $(INDEX).beancount $(INDEX).import "$(EXPANDED_TARGET)" | tee /tmp/extracted.beancount
As you can see, it calls bean-extract
and then pipes the result to a file. On
occasions where the process would fail (under the hood, it calls a bunch of
Python script that parse the different documents), I’d throw a breakpoint()
,
get into pdb
and be annoyed by the lack of completion.
Other times, I’d run the command directly – and readline completion would work, deepening the mystery.
It then dawned on me. In retrospect, it is obvious, and I should have noticed
earlier: well-behaved Unix processes will detect that their standard input is
not a terminal and disable shell completion (often implemented through GNU
readline
).
For CPython, I think the relevant code is here. Entering text into a terminal is indeed complicated.
Mystery solved! Below you can see the behavior in action (you’ll need Javascript enabled, or you can see it here):