Python pexpectモジュール及びshellスクリプトexcept原理解析


expectスクリプト
expectは何ですか
expectは無料のプログラミングツールで、人為的な干渉なしに自動的なインタラクティブタスクを実現します。はっきり言って、expectは自動的なインタラクティブ機能を実現するためのソフトウェアです。
実際の作業では、コマンド、スクリプト、またはプログラムを実行するとき、これらのコマンド、スクリプトまたはプログラムは端末からいくつかの継続的な実行命令を入力する必要がありますが、これらの入力は人工的な手動で行う必要があります。expectを利用すれば、プログラムの提示によって、アナログ標準入力がプログラムに提供され、自動化インタラクティブ実行が可能になります。
Linuxのコマンドのいくつかは、スクリプトの自動化動作にあまり適していません。例えば、fdisk、telnet、ftp接続のダウンロードなどです。だから、exceptを使って交換問題を解決しなければなりません。
exceptの基礎
次の4つのコマンドを含みます。
コマンド
作用
send
プロセスに文字列を送信するために使用します。
except
プロセスから文字列を受信
spwan
新しいプロセスを開始
インターアクト
ユーザーのインタラクションを許可する
  • sendコマンドは、文字列パラメータを受信し、このパラメータをプロセスに送信する。
  • expectコマンドとsendコマンドは反対に、expectは通常、プロセスのフィードバックを待って、対応するインタラクティブコマンドを送信します。
  • spawnコマンドは、新しいプロセスを開始するために使用され、spawn後のsendとexpectコマンドは、spawnを使用して開くプロセスと相互作用します。
  • interact命令用はそんなに多くないです。普通はspawn、sendとexpect命令を使って私達の任務をよく完成できます。しかし、いくつかの特殊な場合にはインターアクトコマンドを使用する必要があります。インターアクトコマンドは主に自動化を解除し、人工的なインタラクションに入るために使用されます。例えば、spawn、send、expectコマンドを使って、ftpをホストに登録して、ダウンロードファイルのタスクを実行しましたが、ファイルのダウンロードが終わったら、ftpコマンドラインの状態に留まり、手動で後続命令を実行します。
  • コードの例
    
    #!/usr/bin/expect
    
    set timeout 30
    set host "101.200.241.109"
    set username "root"
    set password "123456"
    
    spawn ssh $username@$host
    expect "*password*" {send "$password\r"}
    interact
    これは非常に簡単なコードです。基本的な使い方を示しています。
    ヽusr/bin/expect:expectを用いてスクリプトを説明します。
    set timeout 30:タイムアウト時間を設定し、単位は秒で、デフォルトでは10秒です。
    set host「101.241.109」:変数を設定します。
    spawn ssh@username@host:spawnはexpect環境に入ってから実行できるexpect内部コマンドです。もしexpectを入れていないなら、またはデフォルトのSHELLで直接実行してもspawnコマンドは見つけられません。主な機能は、ssh実行プロセスにシェルを追加して、インタラクティブ命令を伝達することです。
    expect「password」:ここのexpectもexpectの内部コマンドです。このコマンドは前回の出力結果に「password」という文字列が含まれているかどうかを判断し、あればすぐに戻ります。しばらく待ってから戻ってきます。ここで待つと30秒前に設定されています。
    send「$password\r」:対応する出力結果に一致すると、開いているsshプロセスにパスワードを送信し、インタラクティブ動作を実行する。
    インターアクト:実行が完了したら、インタラクティブな状態を維持して、コントロールをコンソールに任せてください。この時は手作業で操作できます。これがないとリモート端末に残してはいけません。
    これは上記の簡単なシナリオの分析であり、上記の例では、expectの中の非常に重要な概念であるモード−動作に関するものである。つまり上記のexpect「password」というコードの意味です。
    モード→動作
    expectの「password」というコードを結び付けて、「モード-動作」と言います。簡単に言えば、一つのモードにマッチして、対応する動作を実行します。password文字列にマッチしたらパスワードを入力します。
    以下の通りです
    
    expect {
      "password" {
        send "$password\r"
        exp_continue
      }
      eof
      {
        send "eof"
      }
    }
    その中でもexp_continueは循環式のマッチングを表しています。普通はマッチングしてから文を終了しますが、もしexp_があれば。continueは絶えずマッチングして、複数のコマンドを入力して、書き方を簡略化します。
    参を回す
    多くの場合、私たちはパラメータを台本に送りたいです。今は下記のコードを通じて、expectでパラメータを使う方法を見てみます。
    
    #!/usr/bin/expect
    
    if {$argc < 3} {
      puts "Usage:cmd <host> <username> <password>"
      exit 1
    }
    
    set timeout -1
    set host [lindex $argv 0] 
    set username [lindex $argv 1]
    set password [lindex $argv 2]
    
    spawn ssh $username@$host
    expect "*password*" {send "$password\r"}
    interact
    expectでは、\$argcはパラメータの個数を表していますが、参照値は$argvに保存されています。例えば、最初のパラメータを取ると、「lindex$argv 0」となります。
    FTPダウンロードexpectスクリプト
    yumを使ってexpectをインストールします。
    yum install expect
    次のようにexpectスクリプトを作成します。
    
    #!/usr/bin/expect -f 
    set ip [lindex $argv 0]                           #        ,     IP  
    set file [lindex $argv 1]                          #        ,        
    set timeout 10                                #      10 
    spawn ftp $ip                                 #  ftp $ip  
    expect "Name*"                               #    Name  
    send "anonymous \r"                           #   anoymous(    )   
    expect "Password:*"                           #    Password  
    send "\r"                                     #      
    expect "ftp>*"                                 #    ftp>  
    send "get $file\r"                               #   get $file  
    expect {
      "*Failed*" { send_user " Download failed\r";send "quit\r"}  #         Failed,       ,send_user     Download failed 
      "*send*" { send_user " Download ok\r";send "quit\r"} #         send,       ,send_user     Download ok
      }
    expect eof  #      
    スクリプトに実行可能権限chmod+x expect_を追加します。ftp_at.exp
    pexpectモジュール
    pexpectはlinux下のexpectのpythonパッケージとして理解でき、pexpectを通じてssh、ftp、passwd、telnetなどのコマンドの自動的なインタラクションが可能です。
    pip install pexpectをインストールします。
    簡単なssh自動登録の例は以下の通りです。
    
    import pexpect
    child = pexpect.spwan('scp foo user#expample.com:.')  #spwan  scp  
    child.expect('Password:')          #expect            ,            
                                                #‘Password:'
    child.sendline(mypassword)       #            
    コアコンポーネント
    spawn類
    spawnはpexpectの主な入り口で、機能はサブアプリケーションを起動して制御するので、以下はその構造関数です。
    class pexpect.spwan(command、args=[]、timeout=30、maxread=2000、search windowsize=None、logfile=None、cwd=None、env=None、ignore_sighup=True)
    ここで、commandパラメータは、任意の既知のシステム命令であってもよい。child=pexpect.spawn('user/bin/ftp')サブプログラムにパラメータが必要な場合は、パラメータの代わりにpythonリストを使用することもできます。child = pexpect.spwan('user/bin/ssh [email protected]')パラメータtimeoutは結果待ちのタイムアウト時間であり、maxreadは端末コンソールから一度に読み取られる最大バイト数であり、search windowsizeパラメータは整合するバッファ領域文字列の位置であり、デフォルトでは開始位置からマッチングする。
    注意したいのは、pexpextはshellコマンドの中のメタ文字を解析しません。リダイレクトパイプやワイルドカードを含みます。この時、3つの特殊要素文字のコマンドを/bin/bashのパラメータとして呼び出すことができます。
    child=expect.spwan('/bin/bash-c"ls-l grep LOG'logs.txt")
    child.expect(pexpect.EOF)
    コマンドのパラメータをPYTHONリストに置き換えることで、文法がより明確になります。以下のコードは上のコードと同じです。
    shell_cmd='ls-l grep LOG'logs.txt'
    child=pexpext.spwan('/bin/bash','-c,shell_cmd)
    child.expect(pexpect.EOF)
    デバッグコードの場合は、pexpectの入力と出力情報を取得して、マッチングの状況を把握したいです。一つはログに記入し、もう一つは標準出力に出力します。
    日記に書く
    チdl-pexpect.spwan('some_command
    fout=file('mylogs.txt,'w')
    child.logfile=fout
    標準出力に出力する方法
    child=pexpect.swpan('some_command
    chuld.logfile=sys.stdout
    SSHリモート登録の例を示します。登録が成功したらホームディレクトリのファイルを表示し、入力と出力を記録します。
    
    import pexpect
    import sys
    
    child=pexpect.spawn('ssh [email protected]')
    fout=open('mylog.txt','w')
    child.logfile=fout
    #child.logfile=sys.stdout
    
    child.expect('password:')
    child.sendline('abc@123')
    child.expect('#')
    child.sendline('ls /home')
    child.expect('#')
    expectの方法
    expectはサブルーチン出力の整合規則を定義しています。
    方法定義:expect(pattern、timeout=-1、search windowsize=-1)
    ここで、パラメータpatternは文字列、pexpext.EOF(バッファ領域を指し、マッチング項目がない)、pexpect、TIMEOUT(タイムアウト待ちと一致する)、正規表現またはリストを表します。
    パラメータtimeoutはマッチング結果を待つタイムアウト時間を指定しました。単位は秒で、タイムアウトがトリガされると、expectはpexpext.TIMEOUT、パラメータsearch windowsizeがマッチングするバッファ文字列の位置にマッチします。デフォルトでは開始位置からマッチします。
    read関連方法
    以下の方法の役割は、サブプログラムに応答コマンドを送信することです。
    send(self,s)ハ送命令,回車しない
    sendline(self,s=')は、菗が命令を送り、車を返す。
    snedcontrol(self.chal)菗送信制御文字
    sendeof()菗送eof
    run関数
    runの場合は、pexpextを使用してパッケージの外部コマンドを呼び出す関数です。
    from pexpect import*
    run('scp foo)[email protected]:',events='(i)password':mypassword』)
    pxssh類
    sshセッション操作に対してもう一回パッケージを作ります。
    class pexpext.pxssh.pxssh(timeout=30、maxread=2000、search winddwosize=None、logfile=None、cwd=None、env=None)
    一般的な方法
  • login()ssh接続
  • を確立する。
  • logout()切断
  • promp()は、命令の実行終了を待つためにシステムプロンプトを待っています。
    
    import pxssh
    import getpass
    try:
      s = pxssh.pxssh()                 #    s
      hostname = raw_input('hostname: ')
      username = raw_input('username: ')
      password = getpass.getpass('password: ')  #      
      s.login (hostname, username, password)   #  ssh  
      s.sendline ('uptime') #   uptime  
      s.prompt()       #        
      print s.before     #                 
      s.sendline ('ls -l')
      s.prompt()
      print s.before
      s.sendline ('df')
      s.prompt()
      print s.before
      s.logout()
    except pxssh.ExceptionPxssh, e:
      print "pxssh failed on login."
      print str(e)
    FTP自動操作
    自動インタラクティブ登録FTP操作を実現する。
    
    import pexpect
    import sys
    
    child = pexpect.spawnu('ftp ftp.openbsd.org') #  ftp  
    child.expect('(?i)name .*: ')   #(?!)                  
    child.sendline('anonymous')  #   ftp    
    child.expect('(?i)password')  #      
    child.sendline('[email protected]')  
    child.expect('ftp> ')
    child.sendline('bin')   #       
    child.expect('ftp> ')
    child.sendline('get robots.txt') 
    child.expect('ftp> ')
    sys.stdout.write (child.before)  #     "ftp"          
    print("Escape character is '^]'.
    ") sys.stdout.write (child.after) sys.stdout.flush() child.interact() # Escape character defaults to ^] # , , "^]" child.sendline('bye') child.close()
    以上が本文の全部です。皆さんの勉強に役に立つように、私たちを応援してください。