当目录被删除后如何删除所有的pipenv虚拟环境?

10

我有一个目录 A/,其中包含通过运行 pipenv install 获得的 Pipfile 和 Pipfile.lock。所以这个目录下有一个对应的虚拟环境,位于 /home/username/.local/share/virtualenvs/A-...

然后我删除了这个 A/ 目录。 有没有一种方法可以检查所有的pipenv虚拟环境,找到已删除的目录并删除相应的虚拟环境?

在这种情况下,它应该找到已删除的 A/,并因此删除虚拟环境:/home/username/.local/share/virtualenvs/A-...


主要问题是从虚拟环境名称中找到pipenv运行的目录的完整路径,这个名称只是根目录加上完整路径的哈希值(请参见https://pipenv-fork.readthedocs.io/en/latest/install.html#virtualenv-mapping-caveat)。遍历~/.local/share/virtualenvs中的所有文件夹很容易,但没有映射到创建该虚拟环境的完整路径。 - Gino Mempin
2
如果你做事情很小心,如果你通过requirements.txtPipfile、_poetry_或其他类似的解决方案仔细跟踪属于虚拟环境的项目,那么从头开始重新创建虚拟环境是很便宜的。通常只需要一个命令就可以完成。因此,我倾向于认为一次性删除所有虚拟环境是相对安全的(即使有些可能仍然“存活”),并在需要时重新创建它们。 - sinoroc
是的,这就是我所做的。看起来没有解决方案。可能并不是很有用,因为正如你所说,重新创建它们很容易且便宜。 - Izaya
3个回答

12

pipenv没有特殊的选项。但是您可以使用以下Bash脚本(我使用venvs目录~ / .local / share / virtualenvs /制作了它们,因此如果您的venvs文件夹不同,则应更改它)

打印无用的虚拟环境:

for f in $(find ~/.local/share/virtualenvs/*/.project -type f); do proj_path="$(cat $f)"  && [ ! -d "$proj_path" ] && echo ${f//\/.project};  done;

打印仍然具有对应虚拟环境的不存在的项目路径

for f in $(find ~/.local/share/virtualenvs/*/.project -type f); do proj_path="$(cat $f)"  && [ ! -d "$proj_path" ] && echo $proj_path;  done;

打印输出(无用的虚拟环境和不存在的项目文件夹):

for f in $(find ~/.local/share/virtualenvs/*/.project -type f); do proj_path="$(cat $f)" && [ ! -d "$proj_path" ] && echo $proj_path "\n"${f//\/.project} "\n";  done;

删除无用的虚拟环境

for f in $(find ~/.local/share/virtualenvs/*/.project -type f); do proj_path="$(cat $f)" && [ ! -d "$proj_path" ] && rm -rif ${f//\/.project} && echo DELETING ${f//\/.project};  done;

在删除之前尝试打印venv!

p.s. 如果您的venv文件夹不在~/.local/share/virtualenvs/中,请确保将其更改为您的venv路径!


测试中对于 $proj_path 的引用应该加上引号,以防路径中有空格;[ ! -d "$proj_path" ]。这非常有帮助,谢谢! - phette23
感谢 @phette23,我已经修正了答案。 - yestema

2
这是一个 Bash 脚本,根据 @yestema 的答案交互式地检查和清理废弃的 pipenv 环境。
#!/usr/bin/env bash

# Author: TiDu Nguyen
# https://gist.github.com/tidunguyen/0fc018326f33c29e819be7f388360a5b

# get all pipenv environments
allPipenvEnv=$(find ~/.local/share/virtualenvs/*/.project -type f)

# find abandoned environments
abandonedEnv=()
for f in $allPipenvEnv; do
    proj_path="$(cat $f)" && [ ! -d $proj_path ] && abandonedEnv+=($proj_path)
done

# if there is any abandoned environment, prompt for cleaning, else, exit
if [ ${#abandonedEnv[@]} -eq 0 ]; then
    echo "No abandoned environment, hooray"
else
    echo "Found ${#abandonedEnv[@]} abandoned pipenv environment(s):"
    for value in "${abandonedEnv[@]}"; do
        echo $value
    done

    echo -e "\nClean up abandoned pipenv environments?"
    select choice in "Yes" "No"; do
        case $choice in
        Yes)
            for f in $allPipenvEnv; do
                proj_path="$(cat $f)" && [ ! -d $proj_path ] && rm -rif ${f//\/.project/} && echo DELETING ${f//\/.project/}
            done
            echo "Done!"
            break
            ;;
        No)
            break
            ;;
        esac
    done
fi


1

我基于@yestema的答案编写了一个函数,你可以在我的repo中查看它。 将下面的代码保存到您的个人资料中,例如 ~/.bashrc。

# extra pipenv command
pipenv_correspond(){
  local isDefault=true
  local isLS=true
  local isRM=false

  local show_proj_root=true
  local CORRESPOND=""
  declare -a venvs_root_arr=()
  
  local help_book='Usage: pipenv_correspond [OPTION]\n\nOPTION:
  ls,  --list                list all the corresponding projects_root & venvs
  uls, --useless             list all the not existing projects_roots that still have correspondenting venvs
  npr, --no-project-root     hide projects_root
  rm,  --remove              remove all the venvs from command: "ls" or "uls", deafult is use "uls"
  '
  function Show_root(){
    declare -a venvs_arr=()
    declare -i num_venvs=0
    if $show_proj_root; then
      for f in $(find ~/.local/share/virtualenvs/*/.project -type f); do
        proj_root="$(cat $f)" && [ $CORRESPOND -d $proj_root ] && echo "\nproj: $proj_root\nvenv: ${f//\/.project}\n" && venvs_root_arr+=(${f//\/.project}) && num_venvs+=1
      done
    else
      for f in $(find ~/.local/share/virtualenvs/*/.project -type f); do
        proj_root="$(cat $f)" && [ $CORRESPOND -d $proj_root ] && echo "${f//\/.project}\n" && venvs_root_arr+=(${f//\/.project}) && num_venvs+=1
      done
    fi
    echo "Total venvs: $num_venvs"
  }
  if [ "$#" -gt 0 ]; then
    while [ "$#" -gt 0 ]; do
      case $1 in
        "-h" | "--help" )
          echo $help_book
          return
        ;;
        "ls" | "--list" )
          isDefault=false
          isLS=true
          shift 1
        ;;
        "uls" | "--useless" )
          isDefault=false
          isLS=false
          shift 1
        ;;
        "npr" | "--no-project-root" )
          show_proj_root=false
          shift 1
        ;;
        "rm"  | "--remove" )
          isRM=true
          shift 1 
        ;;
        *)
          echo "\e[31mWrong command keyword!\e[0m" 
          return
        ;;
      esac
    done
  fi
  
  if ! $isLS || ( $isRM && $isDefault ); then
    CORRESPOND="!"
    echo "Useless venvs:"
  else
    echo "Still corresponding venvs:"
  fi

  Show_root venvs_root_arr

  if $isRM; then
    while ! $isDefault && $isLS; do
      printf "\e[33mAre you sure you want to remove all venvs that still existing projects_roots?[y/n] \e[0m"
      read respond
      if [ "$respond" = "n" -o "$respond" = "N" ]; then
        echo "bye~~~"
        return
      elif [ "$respond" != "y" -a "$respond" != "Y" ]; then
        echo "Must type 'y' or 'n'!"
      else
        break
      fi
    done
    echo $venvs_root_arr
    echo "\e[33mWait...\e[0m" 
    for value in ${venvs_root_arr[@]}; do
      echo "remving... $value"
      rm -rf $value
    done
    echo "\e[32mSuccessflly removed all venvs!!\e[0m" 
  fi
}

您的答案可以通过提供更多支持信息来改善。请[编辑]以添加进一步的详细信息,例如引用或文档,以便其他人可以确认您的答案是否正确。您可以在帮助中心找到有关如何编写良好答案的更多信息。 - Community

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接