web-dev-qa-db-ja.com

SSH経由で `cd`コマンドが機能しないのはなぜですか?

SSH経由で一部のファイルをバックアップしようとしていましたが、必要なファイルをtar 'する代わりに、ホームフォルダを取得しました。私はいくつかのさらなるテストを行いました、そしてそれはこれに要約されます:

ssh root@server /bin/sh -c "cd /boot && ls -l"

/rootのファイルを/bootではなく、驚いたことにリストします。しかし、ターミナルから/bin/shコマンド全体を実行すると、正しくcdsされ、/bootファイルが出力されます。

ここで何が起こっているのですか?

41
Ambroz Bizjak

sshでは、リモートホストのexecvpに渡される一連の引数として、コマンドを正確に指定できません。代わりに、すべての引数を文字列に連結し、リモートシェルを介して実行します。これは私の意見ではsshの主要な設計上の欠陥として際立っています...ほとんどの点でそれは行儀の良いUNIXツールですが、コマンドを指定するとき、次のようにargvではなく単一のモノリシック文字列を使用することを選択しましたMSDOSか何かのために設計されました!

Sshはコマンドを単一の文字列としてsh -cに渡すため、独自のsh -cを指定する必要はありません。すると、結果は

sh -c '/bin/sh -c cd /boot && ls -l'

元の引用が失われました。したがって、&&で区切られたコマンドは次のとおりです。

`/bin/sh -c cd /boot`
`ls -l`

最初のコマンドは、コマンドテキスト「cd」と$0 = "boot"を使用してシェルを実行します。 「cd」コマンドは正常に完了し、$0は無関係であり、/bin/sh -cは成功を示し、次にls -lが発生します。

36
user41515

これは引用問題です。 Sshは、シェルで渡したコマンドをすでに実行しています。複数のパラメータを渡す場合、文字列を構築するために、それらの間にスペースが連結されます。したがって、リモートで実行しているリモートコマンドは/bin/sh -c cd /boot && ls -lです(コマンドの引用符はローカルシェルによって解釈されたため、引用符はありません)。

/bin/sh -c cd /boot/bin/shを実行し、cdコマンドを実行し、$0/bootに設定するように指示します。これが完了すると、親Shell(sshdによって起動されたShell)がls -lを実行します。

あなたの場合、リモートシェル(sh -cまたは他のパスワードデータベースに示されている)がこのコマンドを理解できない場合を除いて、完全に役に立たない/etc/passwdを削除してください。

ssh root@server "cd /boot && ls -l"

別のシェルを呼び出す必要がある場合は、sshdによって呼び出されるリモートシェルによる展開から保護するために、リモートコマンドを引用符で囲む必要があります。たとえば、ログインシェルがダッシュで、bashコマンドを実行する場合は、次のようにします。

ssh root@server 'bash -c "cd ~bob && ls -l"'

シェルがオプションをどのように解析しているかにもっと関係があると思います。たとえば、これは動作します:

$ ssh root@server /bin/sh -c '"cd /boot && ls -l"'

これには、コマンドと同じ問題があります。

$ ssh root@server /bin/sh -c 'cd /boot && ls -l'

-vsshに切り替えて、何が起こっているかを確認できます。

最初のコマンド:

debug1:コマンドの送信:/ bin/sh -c "cd/boot && ls -l"

2番目のコマンド:

debug1:コマンドの送信:/ bin/sh -c cd/boot && ls -l

通常、sshを介してコマンドを送信するときは、さまざまなレイヤーがそれらを取り除くため、引用符に特別な注意を払い、引用符内で引用符を囲む必要があります。また、送信しないでください/bin/sh

sshの引用を理解すると、次のような非常に便利なことができます。これにより、リモートサーバーでコマンドが実行されますが、sshコマンドを実行したシステムのローカルのファイルに結果が収集されます。

$ ssh root@server 'free -m' > /tmp/memory.status

または、リモートサーバー上のディレクトリをtarし、ローカルシステム上に作成します。

$ ssh remotehost 'tar zcvf - SOURCEDIR' | cat > DESTFILE.tar.gz

参考文献

8
slm

通常、使用するシェルを指定する必要はありません。これは機能します:

ssh user@Host "cd /boot && pwd"

ただし、デフォルトのシェルに問題がある場合は、シェルの呼び出しを含めてentireコマンドを引用符で囲んでください。以下のいずれかの作品

ssh user@Host '/bin/sh -c "cd /boot && pwd"'
ssh user@Host "/bin/sh -c \"cd /boot && pwd\""
5
tylerl