ys memos

Blog

shellscriptによる自動化でディスク容量を削減する案


shell

2021/10/24

本記事のスクリプトは自由に複製・改変して実行していただいて構いませんが,
それによって生じた損害等の一切の責任は負いかねます.

私自身の環境で動作するために開発しているため,
悪意無く開発しており,
当環境における動作確認は出来ております.

しかし,コンピュータに影響を及ぼすスクリプトですので,
全て自己責任の元でお使い頂くよう,
よろしくお願いいたします.

メインのデスクトップにUbuntuを使っていて,たまにbackupsを使ってバックアップを取っている.

そして私は,Pythonの実行環境の整備にはvenvを,Node.jsにはもちろんnpmを使っている.

その上でバックアップを取ると,どうしても大量の.venvおよびnode_modulesが気になってしまう.

以前,解消方法を模索したことがあり,その時はbackupsFolders to ignoreにワイルドカードが使えるという情報をどこかで見て,設定して試してみたのだが,どうやら適用されていなかったようで,断念した.

今回は,ディスク容量含め抜本的な解決を目指し,シェルスクリプトの関数を作ってみた.


当然,情報量を極力減らさない方法での解決を目指す.


私は普段,Pythonの環境を作成する際には,決まってpython -m venv .venvを使っている.

このように統一することで,カレントディレクトリに.venvがある時に自動アクティベートするという恩恵を得られる.

.venvを消すと,対象の実行環境はきれいに削除される.

また,上述したコマンドでは,クリーンなPython環境が作成され,インストールしてあるパッケージのみで動作可能という前提がある.

pipには,適切な形式のrequirements.txtに対し,pip -r requirements.txtと実行することで,パッケージのバージョンを揃えてくれる機能がある.

requirements.txtは,pip freezeにより生成でき,これによって今のパッケージバージョンを全て記録できる.


npmパッケージのローカルインストールは,package.jsonにパッケージ情報が保存され,package-lock.jsonに詳細なパッケージバージョンを含む情報が保存される.

そして,パッケージの実態は./node_modules内に全て保存される.

ここで,./node_modulesにあるものは全て,npmが存在している限りpackage-lock.jsonから復元可能である.


以上の前提の元,venvおよびnpmに対して必要な処理が決まった.

  1. .venvを見つけ,pip freezeで環境情報をテキストに保存し,.venvを削除
  2. node_modulesを削除
  3. 両者に対し,検出時に削除の可否を求める

function clear_python_venv() {
  source $1/${python_venv_key}/bin/activate
  pip freeze > $1/requirements.txt
  deactivate
  rm -r $1/${python_venv_key}
}

function clear_node_modules() {
  rm -r $1/${node_env_key}
}

function detect_venvs_and_clear() {
  if [ -e "$1/${python_venv_key}" ]; then
    echo ""
    echo "Detect ${python_venv_key} in $1"
    read -p "Do you clear? [y/N]" -r
    if [[ ! $REPLY =~ ^[yN]$ ]]; then
      return
    fi
    echo "Clearing ${python_venv_key}        in $1"
    clear_python_venv $1
  fi

  if [ -e "$1/${node_env_key}" ]; then
    echo ""
    echo "Detect ${node_env_key} in $1"
    read -p "Do you clear? [y/N]" -r
    if [[ ! $REPLY =~ ^[yN]$ ]]; then
      return
    fi
    echo "Clearing ${node_env_key} in $1"
    clear_node_modules $1
  fi
}

function detect_venvs_and_clear_recurse() {
  detect_venvs_and_clear $1
  directories=$(find ${1} -maxdepth 1 -type d -not -name ".*")
  for directory in ${directories[@]}
  do
    if [[ $directory == $1 ]];then
      continue
    fi
    if [[ $directory == "$1/${node_env_key}" ]];then
      continue
    fi
    detect_venvs_and_clear_recurse $directory
  done
}

function clear_venvs_recurse() {
  python_venv_key='.venv'
  node_env_key='node_modules'
  search_path=$PWD
  detect_venvs_and_clear_recurse $search_path
}

スクリプトの内部が気になる方向けの簡単紹介.


pip freezeすると,「現在の」pipでインストールされたパッケージが吐き出されるため,対象となる.venvを起動する必要がある.

そこで,探索ディレクトリの.venv/bin/activateから実行環境を起動し,pip freezeする.

そして,忘れずにdeactivateをした後,.venvを削除する.

function clear_python_venv() {
  source $1/${python_venv_key}/bin/activate
  pip freeze > $1/requirements.txt
  deactivate
  rm -r $1/${python_venv_key}
}

node_modulesを削除する.

function clear_node_modules() {
  rm -r $1/${node_env_key}
}

探索ディレクトリ内に.venv/node_modulesを検出した場合,y/Nを質問する.

安全のため,デフォルトはNoにしており,y/Yのどちらかが入力された場合に,環境を削除する.

function detect_venvs_and_clear() {
  if [ -e "$1/${python_venv_key}" ]; then
    echo ""
    echo "Detect ${python_venv_key} in $1"
    read -p "Do you clear? [y/N]" -r
    if [[ ! $REPLY =~ ^[yN]$ ]]; then
      return
    fi
    echo "Clearing ${python_venv_key}        in $1"
    clear_python_venv $1
  fi

  if [ -e "$1/${node_env_key}" ]; then
    echo ""
    echo "Detect ${node_env_key} in $1"
    read -p "Do you clear? [y/N]" -r
    if [[ ! $REPLY =~ ^[yN]$ ]]; then
      return
    fi
    echo "Clearing ${node_env_key} in $1"
    clear_node_modules $1
  fi
}

内部で再帰的に呼ばれる関数.

$1は探索対象となるディレクトリとした.

呼び出し時に,.venv/node_modulesを検出し,削除を確認し,処理する.

findコマンドにより探索ディレクトリ内のディレクトリを新しい探索ディレクトリとし,再帰する.この時,隠しファイルとなっているディレクトリは無視する.

また,node_modulesの中には無数のnode_modulesが含まれており,それを内包するnode_modulesを削除せずに内部の特定のnode_modulesを削除するパターンは基本的に無いと考え,探索対象から除外する.

function detect_venvs_and_clear_recurse() {
  detect_venvs_and_clear $1
  directories=$(find ${1} -maxdepth 1 -type d -not -name ".*")
  for directory in ${directories[@]}
  do
    if [[ $directory == $1 ]];then
      continue
    fi
    if [[ $directory == "$1/${node_env_key}" ]];then
      continue
    fi
    detect_venvs_and_clear_recurse $directory
  done
}

シェルスクリプトからの呼び出しに便利なように,再帰関数を囲む関数を準備した.

実際に呼び出す関数はこれになる.

利便性向上の為,キーをここで指定する.

function clear_venvs_recurse() {
  python_venv_key='.venv'
  node_env_key='node_modules'
  search_path=$PWD
  detect_venvs_and_clear_recurse $search_path
}

シェルスクリプト書くのまじつらい・・・

繰り返しになりますが,
コードは自由に複製・改変いただけますが,
全て自己責任でご利用ください.

関連タグを探す