なぽろぐ

気ままに感じたことを記事にまとめます。

expectでシェルと会話できる!人間同士の会話も自動化したいなぁ

expectを使ってみたよ!ってだけの記事

1ヶ月に1回くらいSFTPからデータ取ってきて適当に加工するみたいなタスクがあって、毎回ダウンロードして、zipファイル解凍して〜ってやるのがめんどくさくて、自動化するぞ〜!!ってなったのが始まりです。

作ったスクリプト

#!/bin/sh

PW="なんかパスワード入れる"

expect -c "
set timeout -1
spawn env LANG=C /usr/bin/sftp -oPort=ポート番号 user@host:dir
expect \"password:\"
send \"${PW}\n\"
expect \"sftp>\"
send \"get $1\n\"
expect \"sftp>\"
send \"quit\n\"
"

ファイル名がdownloadSFTP.shとかにして、

sh downloadSFTP.sh ダウンロードしたいファイル名

にすると勝手にログインしてダウンロードしてくれます。楽でいいですね。

expect -c の中身

set timeout

  • expectが終了する時間を指定することができる
  • デフォルトは10秒
  • -1を指定するとexpectに書いた処理が終わるまで待つことができる

spawn

  • 実行したいコマンドを指定

expect

  • ""の中に書いた文字と一致したら次の行を実行するコマンド。つよい。うれしい。これがすき

send

  • 対話シェル入力するコマンド
  • パスワードとか書いておくと自動化できていいね
    • パスワード平文でshell script内に保存することになるんですけど、それはいいのか?とか思いながらだるい気持ちの方が上回ったのでそのまま書いています

interact

今回はつかってません - これを使えばexpectが終了してユーザーが入力できるようになります。 - sshログインした後にこれ書けばいいんじゃない?

本当はPythonから直接SFTP叩きたかった

もともとはPythonでSFTPに接続してDLしてこようと思ったんですけど、うまいこと動かなかったのでlinuxコマンドを使って自動化してみました。Pythonからは次のような感じで呼び出して使っています。

import subprocess

def download_sftp(file_name):
  shell_dir = 'shellscript'
  shell_script_name = 'downloadSFTP.sh'
  script_path = os.path.join(shell_dir, shell_script_name)

  shell_output = subprocess.Popen(
                  ['sh', script_path, file_name],
                  stdout = subprocess.PIPE,
                  stderr = subprocess.PIPE)
  
  out, err = map(
    lambda b: b.decode('utf-8'),
    shell_output.communicate()
  )

  return out, err

最後に

普通にいい感じで動いているのであとはデーモンにして常駐させようかなって思っています。毎日0時に起動する感じにすれば、自分の仕事が減るのでサボっててもなんとかなりそうですね。

あとtreeコマンドいいですね f:id:Naporitan:20190403210900p:plain ディレクトリ構成すぐ出るのでパッとわかりやすいですね

これつくってる時にめっちゃ困ったことが発生して、今も困っているんですけど f:id:Naporitan:20190403210555p:plain これ何?

ファンが死ぬほど回っててつらい