SFTPサイトに接続していくつかのファイルをアップロードするExpectスクリプトがあります。 IDとパスワードはローカルテキストファイルに含まれています。 expectスクリプトは、これらのファイルを変数として読み取り、SFTPサーバーに渡します。
私が経験している問題は、特殊文字($\,!)などを含む複雑なパスワードが提供されていることです。たとえば、パスワードがpass $ Wordの場合、$はリテラルではなく特殊文字として渡されます。これが変数を介して渡されている(複数のサイトとID)
「$ pw」を使用できません。文字どおり$ pwをサーバーに渡し、「$ pw」を使用すると特殊文字が送信されます。そのままパスワードを渡す必要があります。
私はこれまで手でそれらをエスケープしてきました(例:pass\$ Word)。
スクリプトは次のようになります(名前と場所は無実を保護するために変更されました)
#!/bin/bash
home=/data/ftp/vf/drop/
un=`cat /home/vf/workflow/.udf/.u/.u$1`
pw=`cat /home/vf/workflow/.udf/.p/.p$1`
sl=`cd /home/vf/workflow/scheduler; grep $1 upload*|cut -d \: -f1`
/usr/bin/expect -c "
spawn /usr/bin/sftp -o KexDHMin=1024 $un@$sl.mysteriouslocation.com
set timeout -1
expect *Authentication
expect Password*
send \"$pw\r\"
expect sftp*
send \"mput /$home/$1/transfer/*\r\"
expect sftp*
send \"ls \r\"
expect sftp*
send \"bye\r\"
expect eof
exit
パスワードをexpectスクリプトに渡し、リテラル文字を送信して特別な意味を与えないようにするにはどうすればよいですか?パスワードファイル自体の「修正」をスクリプト化することはできないと思います。つまり、特殊文字が表示されるたびに、sedまたはその他の手段でエスケープ文字自体が特殊であり、最終的にはループ。
あなたの助けは大歓迎です!
小さなPerlスニペットを使用して、すべてのASCIIと一致しない文字をエスケープ(バックスラッシュ)することができます/[A-Za-z_0-9]/
quotemeta 関数を使用します。 Perlコマンドラインはシェルスクリプトに簡単に組み込むことができます。
#/bin/sh
pstr='$x%y!zpass' # plain, un-escaped string
estr=$(Perl -e 'print quotemeta shift(@ARGV)' "${pstr}")
echo ${estr} # show escaped string
生成する:
\$x\%y\!zpass
値を環境変数として渡します。また、コマンドインジェクションの脆弱性を回避し、ps
出力にパスワードを表示します。
#! /bin/sh -
home=/data/ftp/vf/drop
un=$(cat /home/vf/workflow/.udf/.u/.u"$1")
pw=$(cat /home/vf/workflow/.udf/.p/.p"$1")
sl=$(cd /home/vf/workflow/scheduler &&
grep -Fe "$1" upload*|cut -d : -f1)
export home un sl pw
user=$1 /usr/bin/expect -c '
spawn /usr/bin/sftp -o KexDHMin=1024 $env(un)@$env(sl).mysteriouslocation.com
set timeout -1
expect *Authentication
expect Password*
send $env(pw)\r
expect sftp*
send "mput /$env(home)/$env(user)/transfer/*\r"
expect sftp*
send ls\r
expect sftp*
send bye\r
expect eof
exit'
(まあ、変数にsftp
が!reboot
のようなコマンドを実行するようなテキストが含まれている場合は、コマンドインジェクションの脆弱性である可能性があります)。
Expectプログラムを別のスクリプトに入れ(sftp.expect
としましょう)、ユーザー名/パスワードを引数として渡します。
これには、コマンドライン引数がシステムの他のユーザーに表示されるという問題があります。これは、パスワードを処理するための最良の方法ではありません。あなた本当に共有システムのパスワードに対してこれをしたくない。
#!/usr/bin/expect -f
set un [lindex $argv 0];
set pw [lindex $argv 1];
set sl [lindex $argv 2];
spawn /usr/bin/sftp -o KexDHMin=1024 $un@$sl.mysteriouslocation.com
set timeout -1
expect *Authentication
expect Password*
send "$pw\r"
それからシェルスクリプトからそれを実行します
#!/bin/bash
un=$(cat /home/vf/workflow/.udf/.u/.u"$1")
pw=...
sl=...
expect -f sftp.expect "$un" "$pw" "$sl"
または、期待するスクリプトを同じシェルスクリプト内に保持したい場合は、ヒアドキュメントに貼り付けます。
#!/bin/bash
un=foo
# ...
expect -f - "$un" <<'EOF'
set un [lindex $argv 0];
send "user is: $un\r\n"
# ...
EOF
(EOF
の前後の引用符に注意してください。シェルがヒアドキュメントの変数を解釈しないようにする必要があります。)