ssh
リモートでコマンドを実行しようとしています。ただし、呼び出しコマンドを次の変数として保存します。
SSH_CMD="ssh -i path_to/identity"
SSH_USER=user
SSH_DST=server
dir1=dir1
dir2=dir2
今私は
eval $SSH_CMD $SSH_USER@$SSH_DST "mkdir $dir1 && mv $dir1 $dir2 && touch $dir2"
エラーが発生します(通常mv: cannot stat 'dir1': No such file or directory
:)。
しかし、もし私が:
ssh -i path_to/identity $SSH_USER@$SSH_DST "mkdir $dir1 && mv $dir1 $dir2 && touch $dir2"
これはうまくいきます。だから問題は私がどのようにするのだろうかeval
。正しいアプローチは何ですか?
答え1
eval $SSH_CMD $SSH_USER@$SSH_DST "mkdir $dir1 && mv $dir1 $dir2 && touch $dir2"
これは実際に実行するのと同じです。
eval "$SSH_CMD $SSH_USER@$SSH_DST mkdir $dir1 && mv $dir1 $dir2 && touch $dir2"
eval
単一の文字列で取得した引数を連結し、シェルコマンドで実行します。特に&&
ジョブはローカル側で実行されるため、シェルが最初に実行され、成功するとリモートホストssh ... mkdir dir1
で実行mv dir1 dir2
などが実行されますが、ローカルホストでは実行されません。mkdir
mv
dir1
ここでは使用する必要はありませんeval
。最初のコマンドには必要ありません。
$SSH_CMD $SSH_USER@$SSH_DST "mkdir $dir1 && mv $dir1 $dir2 && touch $dir2"
$SSH_CMD
いついいえ引用後ご希望のとおり、、3つのssh
単語-i
に分けて作成いたします。path_to/identity
これはうまくいきますが、少し不潔で、$SSH_CMD
スペースを含むパラメータを含める必要がある場合、またはグローバル文字を使用する必要がある場合に問題が発生する可能性があります。
可変数のコマンド引数(例:)を保存する必要がある場合は、 SSH_CMD
配列を使用することをお勧めします。また、トークン化を防ぐために他の変数が引用されます。
ssh_cmd=(ssh -i path_to/identity)
ssh_user=user
ssh_host=server
dir1=dir1
dir2=dir2
"${ssh_cmd[@]}" "$ssh_user@$ssh_host" "mkdir $dir1 && mv $dir1 $dir2 && touch $dir2"
バラよりBashFAQ 050:コマンドを変数に入れようとしていますが、複雑な場合は常に失敗します。そして変数に保存されたコマンドをどのように実行できますか?詳細については。
答え2
ここで使用する理由はありませんeval
。命令に潜在的な穴がたくさん出るだけです。
可能であれば、次の変数ではなく配列にオプションを保存する必要があります。
SSH_OPTS=( -i path_to/identity )
SSH_USER=user
SSH_DST=server
dir1=dir1
dir2=dir2
それではあなたは確かにしなければなりません。いつも変数を二重引用符で囲みます。
ssh "${SSH_OPTS[@]}" "${SSH_USER}@${SSH_DST}" "mkdir $dir1 && mv $dir1 $dir2 && touch $dir2"