Windows ユーザだとリモート接続に PuTTY を、ファイル転送に WinSCP を使っているケースは多いと思います。が、「リモートマシンにこれを送って、これを実行して、これを回収する」というのが固まってきたら、これらでの GUI 操作は面倒です。そこで、PuTTY 付属 CLI ツール plink / pscp を利用すると、PuTTY 用の鍵をそのまま使って一連の操作をバッチ実行できます。
PuTTY 付属 CLI ツール plink / pscp とは
PuTTY に同梱されているコマンドラインツールです (ツールは他にもあります)。
-
plink: SSH 接続します (対話シェルを開始するだけでなく、バッチ実行もできます)。
- ドキュメント: Using the command-line connection tool Plink
- 例:
plink -i key.ppk ubuntu@xxx.xxx.xxx.xxx(ログインして対話シェルを開始する)- リモートで作業できます。が、矢印キーでコマンド履歴を呼び出せないなど制限があるので本格的に作業するなら PuTTY でログインした方が便利だと思います。
- 例:
plink -i key.ppk ubuntu@xxx.xxx.xxx.xxx -batch "cd result && cat log.txt"(渡したコマンドを実行して終わる)- コマンドを渡すことができます。
-batchで対話要求を拒否できます。- 対話要求を拒否するので、
-batch使用前に一度は PuTTY 本体か対話モードでログインしておかないと、The server's host key is not cached in the registry ... (初回ログイン時のメッセージ) となるのを許可できず失敗します。
- 対話要求を拒否するので、
- コマンドを渡すことができます。
-
pscp: SCP でファイル転送します。
- ドキュメント: Using PSCP to transfer files securely
- 例:
pscp -i key.ppk ./config.toml ubuntu@xxx.xxx.xxx.xxx:/home/ubuntu/ - 例:
pscp -r -i key.ppk ubuntu@xxx.xxx.xxx.xxx:/home/ubuntu/result/ ./- ディレクトリごと転送するときには
-rが必要です。
- ディレクトリごと転送するときには
使用例
以下のシェルスクリプトはすべて Git Bash での実行を想定しています。
リモートファイルの存在を確認する
以下でリモートに config.toml が存在するか確認できます。
#!/usr/bin/bash
key=~/.ssh/key.ppk
remote=ubuntu@xxx.xxx.xxx.xxx
plink -i $key $remote -batch "test -f config.toml"
if [ "$?" -eq "0" ]; then
echo "あります"
else
echo "ないです"
fi
リモートの pyenv 環境で処理を実行する
以下でリモートの pyenv 環境で処理を実行できます (plink は非対話では ~/.bashrc を実行しないので、pyenv 用に ~/.bashrc に記述している処理を改めて記述します)。
#!/usr/bin/bash
key=~/.ssh/key.ppk
remote=ubuntu@xxx.xxx.xxx.xxx
remote_dir=workspace/project001
batch="export PYENV_ROOT=\$HOME/.pyenv;"
batch="${batch} export PATH=\$PYENV_ROOT/bin:\$PATH;"
batch="${batch} eval \"\$(pyenv init - bash)\";"
batch="${batch} source torch-env/bin/activate;"
batch="${batch} cd ${remote_dir};"
batch="${batch} python run.py"
plink -i $key $remote -batch "$batch"
リモートで処理を起動だけして SSH 接続を切断する
処理を起動だけして SSH 接続を切断したい場合、nohup 処理 > /dev/null 2>&1 < /dev/null & exit でできます (標準入出力を /dev/null にしないと待機してしまいます)。
#!/usr/bin/bash
key=~/.ssh/key.ppk
remote=ubuntu@xxx.xxx.xxx.xxx
remote_dir=workspace/project001
batch="$cd ${remote_dir};"
batch="${batch} nohup 処理"
batch="${batch} > /dev/null 2>&1 < /dev/null & exit"
plink -i $key $remote -batch "$batch"
ユースケース: リモート pyenv 処理を起動・監視・回収するスクリプト
torch-env 環境でプロジェクトルート以下で python -m my_module conf_001.toml と実行すると、conf_001/ 以下に進捗状況 log.txt を含む成果物を出力するプロジェクトがあるとします。これをリモートで実行する便利スクリプトが以下です。
-
./remote.sh conf_001 (action)と実行します。action は後で指定もできます。-
s(send) を選択すると、ローカルの設定ファイルを送信して処理を開始します。 -
m(monitor) を選択すると、成果物一覧とlog.txtの中身を表示します。-
log.txtがまだなければ表示せず終わります。実際には処理が何段階もあるので、「処理 1 のログがあれば表示」「処理 2 のログがあれば表示」… としています。
-
-
c(collect) を選択すると、成果物conf_001/を回収します。
-
#!/usr/bin/bash
# ---------- 設定記入 ----------
key=~/.ssh/key.ppk
remote=ubuntu@xxx.xxx.xxx.xxx
remote_dir=workspace/project001
remote_fullpath=${remote}:/home/ubuntu/${remote_dir}
module=my_module
# ---------- 訓練実行 ----------
send_conf_and_exec() {
# 訓練設定ファイル送信
local batch="cd ${remote_dir} && ls ${target_toml}"
plink -i $key $remote -batch "$batch"
if [ "$?" -eq "0" ]; then
echo "リモートに訓練設定ファイルが既に存在します"
return 1
fi
pscp -r -i $key ./${target_toml} ${remote_fullpath}/${target_toml}
# 訓練実行
batch="export PYENV_ROOT=\$HOME/.pyenv;"
batch="${batch} export PATH=\$PYENV_ROOT/bin:\$PATH;"
batch="${batch} eval \"\$(pyenv init - bash)\";"
batch="${batch} source torch-env/bin/activate;"
batch="${batch} cd ${remote_dir};"
batch="${batch} nohup python -m ${module} ${target_toml}"
batch="${batch} > /dev/null 2>&1 < /dev/null & exit;"
plink -i $key $remote -batch "$batch"
}
# ---------- 状況確認 ----------
monitor() {
echo "===== ${target} ====="
local batch="cd ${remote_dir} && ls ${target}/"
batch="${batch} && [ -f ${target}/log.txt ]"
batch="${batch} && echo \"----- ${target}/log.txt -----\""
plink -i $key $remote -batch "$batch"
}
# ---------- 結果回収 ----------
collect() {
pscp -r -i $key ${remote_fullpath}/${target} ./${target}
}
# ========== メイン処理 ==========
target="$1"
target_toml=${target}.toml
action="$2"
if [ ! -f "${target_toml}" ]; then
echo "存在しません: ${target_toml}"
exit 1
fi
if [ -z "$action" ]; then
echo "${target} への操作を選択してください"
read -p "s=訓練実行, m=状況確認, c=結果回収 > " action < /dev/tty
fi
case "$action" in
s)
echo "訓練実行します:"
send_conf_and_exec ;;
m)
echo "状況確認します:"
monitor ;;
c)
echo "結果回収します:"
collect ;;
esac