hash cache in bash
Not funny and obsolete
Yesterday I’ve learned one more thing from the past I didn’t want to know. I could justify it at the time of invention, but I think it’s obscure, rotten and bringing too much of ‘deep internal world’ of some mundane utility onto users of modern systems.
It’s called ‘executable caching’. When you call some binary for the first time, bash caches the path for that binary. You can see it by calling hash
. This is built-in command in bash. It shows you what commands you’ve called, how many times and their paths.
When it breaks?
I tried to use new Ansible in .venv. I sourced .venv/bin/activate
, called ansible-playbook (original one, installed in my system), pip-installed new ansible. I checked version: ansible --version
was new. I then ran ansible-playbook, and it rejected to work on my playbook, as I always have ‘version lock’ on my playbooks:
- hosts: all, localhost
gather_facts: false
run_once: true
tasks:
- name: Check ansible lower version
assert:
that: "ansible_version.full | version_compare('2.8.0', '>=')"
msg: >
"You must update Ansible to at least 2.8"
- name: Check upper ansible version
assert:
that: "ansible_version.full | version_compare('2.9.0', '<')"
msg: >
"You must downgrade Ansible to 2.8 to run this playbook"
delegate_to: localhost
tags:
- always
It complained I’m still on 2.7. ansible says version is 2.8.something. I run ansible-playbook --version
and it said 2.7! With system paths. And ansible said it’s 2.8 and on .venv. which for ansible-playbook said “.venv!”, and PATH was set right (with .venv at front).
Of course, the reason was that call of ansible-playbook after .venv but before running pip install ansible. Bash has cached the location of the ansible-playbook binary and wasn’t intended to search for it again.
They saved few syscalls (premature optimization) and cause big WTF for users.
How to disable it?
shopt -u checkhash
into ~/.bashrc
.
How to fix it right away? hash -r
.