Skip to content

Instantly share code, notes, and snippets.

@pfheatwole
Last active April 12, 2023 14:55
Show Gist options
  • Save pfheatwole/a298e5698eeb517f770b68c154b9682c to your computer and use it in GitHub Desktop.
Save pfheatwole/a298e5698eeb517f770b68c154b9682c to your computer and use it in GitHub Desktop.
pyenv plugin to scan for dependent virtual environments
#!/usr/bin/env bash
#
# Summary: Find virtual environments that use pyenv-managed versions.
#
# Usage: pyenv users [directory]
#
# Scans [directory] for virtual environments whose `python` commands
# are symlinks back into a pyenv version. Default: current directory.
#
# I'm not a script writer so it's probably a bit crude, but I find it
# helpful for checking if I can uninstall old Python versions. Uses
# the `column` command from the util-linux package (if available) for
# pretty-printing the output.
if [ -n "$1" ]; then
DIR="$1"
else
DIR="$PYENV_DIR"
fi
cmd="readlink -f '{}' | grep -q ${PYENV_ROOT}"
unset links i
while IFS= read -r -d $'\0' file; do
links[i++]="$file"
done < <(find -H "$DIR" -name "python" -type l -exec sh -c "$cmd" \; -print0)
# Exit if no relevant venvs were found
if [[ $i -eq 0 ]]; then
exit 0
fi
# Use columnar output if convenient.
if [ -n "$(command -v column)" ]; then
output="column -t -s ':'"
else
output="cat"
fi
# Regex to extract the pyenv version from the target string. The
# second group consumes the actual binary (`python`, `pypy3`, etc)
regex="${PYENV_ROOT}/versions/(.+)/bin/(.+)"
for link in "${links[@]}"; do
# `$link` is the `python` symlink, and `$target` is its target.
target=$(readlink -f "$link")
# Ignore symlinks inside $PYENV_ROOT itself
if realpath -s "$link" | grep -v -q "$PYENV_ROOT"; then
[[ "$target" =~ $regex ]]
version="${BASH_REMATCH[1]}"
echo "$version":"${link%/bin/python}"
fi
done | sort | $output
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment