Created
February 25, 2026 17:40
-
-
Save Ge0rg3/947c4b97754f30b854772aaf79889c0b to your computer and use it in GitHub Desktop.
Bash script to select conda envs dynamically
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #!/usr/bin/env bash | |
| # conda.sh - interactive conda env selector | |
| # Must be sourced: source /path/to/conda.sh | |
| # Must be sourced for activation to affect the current shell. | |
| if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then | |
| echo "This script must be sourced: source conda.sh" >&2 | |
| exit 1 | |
| fi | |
| # Selection runs in a subshell so strict-mode does NOT leak into your shell | |
| _selected="$( | |
| ( | |
| set -euo pipefail | |
| fail() { echo "Error: $*" >&2; exit 1; } | |
| ensure_conda() { | |
| command -v conda >/dev/null 2>&1 || fail "conda not found in PATH. Run: conda init bash, then restart your shell." | |
| } | |
| get_pyver() { | |
| local prefix="$1" | |
| local pbin="$prefix/bin/python" | |
| if [[ -x "$pbin" ]]; then | |
| "$pbin" -c 'import sys; print(".".join(map(str, sys.version_info[:3])))' 2>/dev/null && return 0 | |
| fi | |
| conda run --prefix "$prefix" python -c 'import sys; print(".".join(map(str, sys.version_info[:3])))' 2>/dev/null || echo "N/A" | |
| } | |
| collect_envs() { | |
| mapfile -t ENVS < <( | |
| conda env list 2>/dev/null \ | |
| | awk ' | |
| NF==0 {next} | |
| $1 ~ /^#/ {next} | |
| { | |
| name=$1 | |
| if ($2=="*") { path=$3 } else { path=$2 } | |
| if (name != "" && path != "") print name "\t" path | |
| } | |
| ' | |
| ) | |
| ((${#ENVS[@]} > 0)) || fail "No conda environments found." | |
| } | |
| build_display_lines() { | |
| LINES=() | |
| for row in "${ENVS[@]}"; do | |
| name="${row%%$'\t'*}" | |
| path="${row#*$'\t'}" | |
| pyver="$(get_pyver "$path")" | |
| LINES+=("${name}"$'\t'"py${pyver}"$'\t'"${path}") | |
| done | |
| } | |
| choose_with_fzf() { | |
| printf "%s\n" "${LINES[@]}" \ | |
| | fzf --height=40% --layout=reverse --border \ | |
| --prompt="conda env> " \ | |
| --header=$'NAME\tPYTHON\tPATH' \ | |
| --delimiter=$'\t' \ | |
| --with-nth=1,2,3 | |
| } | |
| choose_with_select() { | |
| echo "fzf not found; using numbered menu." >&2 | |
| echo >&2 | |
| local i=1 | |
| for l in "${LINES[@]}"; do | |
| local name py | |
| name="${l%%$'\t'*}" | |
| py="$(awk -F'\t' '{print $2}' <<<"$l")" | |
| printf "%2d) %s (%s)\n" "$i" "$name" "$py" >&2 | |
| ((i++)) | |
| done | |
| echo >&2 | |
| read -rp "Select env number: " n | |
| [[ "$n" =~ ^[0-9]+$ ]] || fail "Invalid selection." | |
| (( n >= 1 && n <= ${#LINES[@]} )) || fail "Selection out of range." | |
| printf "%s\n" "${LINES[$((n-1))]}" | |
| } | |
| select_env() { | |
| if command -v fzf >/dev/null 2>&1; then | |
| choose_with_fzf || true | |
| else | |
| choose_with_select || true | |
| fi | |
| } | |
| ensure_conda | |
| collect_envs | |
| build_display_lines | |
| selected="$(select_env)" | |
| [[ -n "${selected}" ]] || exit 0 | |
| printf "%s\n" "$selected" | |
| ) | |
| )" || return 0 | |
| # user cancelled | |
| [[ -n "${_selected}" ]] || return 0 | |
| sel_path="$(awk -F'\t' '{print $3}' <<<"$_selected")" | |
| sel_name="$(awk -F'\t' '{print $1}' <<<"$_selected")" | |
| sel_py="$(awk -F'\t' '{print $2}' <<<"$_selected")" | |
| conda activate "$sel_path" | |
| printf "Activated: %s (%s)\n" "$sel_name" "$sel_py" |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment