シェルスクリプトからcondaコマンドを活用したいとき

こんにちは!
今日はみんな大好きcondaコマンドについてです。
condaコマンドで仮想環境に入って、何らかの処理をして、戻ってくる ようなシェルスクリプト、バッチタスクをやるときのTipsです。
AI開発において、Anacondaとその中核であるcondaパッケージマネージャーはとっても重宝します。
しかし、シェルスクリプトから自動的にcondaを利用しようとすると、意外なハードルがあります。
本記事では、シェルスクリプトからcondaコマンドを正しく呼び出す方法について解説します。
condaと非対話モードの課題
AnacondaがインストールされているLinux環境において、condaコマンドは通常、.bashrc
や.bash_profile
などの設定ファイルによって初期化されます。
なんとなくシェルをつかっていると、このcondaコマンドの初期化を忘れてしまいますが、これらの設定は多くの場合シェルの「対話モード」でのみ有効になるように設計されています。
ゆえにシェルスクリプトのような非対話モードでは、condaコマンドが正しく機能してくれません
例えば、.bashrc
ファイル内のconda初期化部分には、以下のような条件が含まれています
# >>> conda initialize >>>
if [[ $- == *i* ]]; then # 対話モードの場合のみ実行
. "/path/to/anaconda3/etc/profile.d/conda.sh"
fi
# <<< conda initialize <<<
ここでの if [[ $- == *i* ]]
が対話モードチェックであり、シェルスクリプトのような非対話環境では、この条件に合致せずconda初期化が行われません。
つまりシェルスクリプトの中でcondaコマンドがうまく動いてくれません。
解決策→enable_conda.shスクリプト
この問題を解決するために、以下のようなスクリプトを作成しましょう
#!/bin/bash
###[enable_conda.sh]###########################################################
# condaの初期化を明示的に行う
# ~/.bashrcの対話モードチェックをバイパスするために、条件部分を直接実行する
# ユーザーのホームディレクトリを使用
CONDA_PATH="$HOME/anaconda3"
# condaの初期化部分を直接実行
__conda_setup="$('$CONDA_PATH/bin/conda' 'shell.bash' 'hook' 2> /dev/null)"
if [ $? -eq 0 ]; then
eval "$__conda_setup"
else
if [ -f "$CONDA_PATH/etc/profile.d/conda.sh" ]; then
. "$CONDA_PATH/etc/profile.d/conda.sh"
else
export PATH="$CONDA_PATH/bin:$PATH"
fi
fi
unset __conda_setup
# パスを確認
echo "使用するcondaのパス: $(which conda)"
echo "condaのバージョン: $(conda --version)"
###[/enable_conda.sh]#########################################################
このスクリプトでは、
- 対話モードチェックをバイパスして、直接conda初期化コードを実行します
- 環境変数を適切に設定し、condaコマンドをシェルスクリプト中からも使用可能にします
sourceコマンドの重要性
さて、このスクリプトの効果を得るためには、これをsource
コマンドをつかって実行するのがポイントです
source ./enable_conda.sh
# または
. ./enable_conda.sh # ドットコマンド(sourceと同等)
復習)sourceコマンドとは?
source
コマンドは、指定されたファイル内のコマンドを現在のシェルプロセス内で直接実行するためのシェルビルトインコマンドです。これには以下のような特徴があります
- ファイル内のコマンドが現在のシェルプロセス内で実行される
- 環境変数の変更やエイリアスの定義など、シェルの状態変更が現在のセッションに反映される
.
(ドット)コマンドと同じ機能を持つ
sourceと直接実行の違い
普段あまり気にしていませんが、スクリプトを直接実行する場合との違いは以下のようになります
実行方法 | プロセス | 環境変数への影響 | Condaの場合 |
---|---|---|---|
sh script.sh |
新しいシェルプロセス(子プロセス)を作成 | スクリプト内で設定された環境変数は終了後に失われる | 初期化は子プロセスでのみ有効、親シェルではcondaコマンドは使えない |
source script.sh |
現在のシェルプロセス内で直接実行 | 環境変数の変更が現在のシェルに保持される | 現在のシェルでconda初期化が行われ、以降condaコマンドが使える |
Condaのような環境管理ツールを初期化するスクリプトでは、現在のシェル環境に変更を反映させる必要があるため、必ずsource
コマンドを使用しましょう
実践的な使用例
以下のように使用することができます
バッチ処理スクリプト
#!/bin/bash
# データ処理バッチジョブ
# condaを初期化
source /path/to/enable_conda.sh
# 特定の環境をアクティベート
conda activate myenv
# Pythonスクリプトを実行
python /path/to/process_data.py
# 処理完了後、基本環境に戻る
conda deactivate
定期実行(cron)ジョブ
crontabファイル:
# 毎日午前2時にデータ更新を実行
0 2 * * * /bin/bash /path/to/daily_update.sh
daily_update.sh:
#!/bin/bash
# conda初期化
source /home/user/scripts/enable_conda.sh
# 環境をアクティベート
conda activate analysis_env
# スクリプト実行
python /home/user/projects/update_database.py
# ログ出力
echo "$(date): データベース更新完了" >> /home/user/logs/cron.log
上記のようにスクリプトを別ファイルにしなくてもそんなにながくないので、実行していスクリプトに直接conda初期化コードを入れてしまってもOKですね
まとめ
シェルスクリプトからcondaコマンドを使用するには
- 対話モードチェックをバイパスする初期化スクリプト(enable_conda.sh)を作成する(またスクリプトに入れちゃってもOK)
- 外部スクリプトにする場合は、それを
source
コマンドで実行し、現在のシェル環境にconda設定をおぼえさせる - 環境変数を活用して、異なる環境でも再利用可能にする
ということで、シェルスクリプトのなかで気軽にcondaが使えるようになりました!