ssh localhost sh -c 'echo "$0"' arg0が何も出力しないのはなぜですか?

ssh localhost sh -c 'echo "$0"' arg0が何も出力しないのはなぜですか?

〜のようにechoが/bin/sh -c echo fooと呼ばれ、何も出力しないのはなぜですか?しかしssh、。

なぜ何も出力されないのですか?

ssh localhost sh -c 'echo "0=$0 1=$1"' arg1 arg2 arg3

しかし、私はそれを次のように変更すると

ssh localhost sh -c 'true; echo "0=$0 1=$1"' arg1 arg2 arg3
# Output is
0=bash 1= arg1 arg2 arg3

私が見ている動作は、echoコマンドが実行されているが変数の置換が期待どおりに機能しないことを示します。バラよりhttps://unix.stackexchange.com/a/253424/119816

SSHなしで実行すると、期待どおりに機能します。

上記と同じですが、sshコマンドを削除しました。

sh -c 'echo "0=$0 1=$1"' arg1 arg2 arg3
# Output is
0=arg1 1=arg2

# Adding true gives same output
sh -c 'true; echo "0=$0 1=$1"' arg1 arg2 arg3
0=arg1 1=arg2

あるマシンから別のマシンにルートアクセス可能ファイルをコピーしようとしています。

sshコマンドを使用してルートファイルを別のシステムにコピーしようとしています。私が試しているコマンドは次のとおりです。

file=/etc/hosts
set -x
ssh host1 sudo cat $file | ssh host2 sudo sh -c 'exec cat "$0"' $file
# Output is
+ ssh host2 sudo sh -c 'exec cat > "$0"' /etc/hosts
+ ssh host1 sudo cat /etc/hosts
bash: : No such file or directory

私の目には問題ないようですが、問題を解決する方法がわかりません。

私のソリューション

私の解決策は、以前使用したものに戻ることでした。

ssh host1 sudo cat $file | ssh host2 sudo tee $file > /dev/null

上記は有効です。

解決策を探す

私はこの問題に直面して、次の質問をしました。

他の人は次のコマンドに問題/質問がありますsh -c

ただし、sshを使用すると、追加のシェル評価が発生する微妙な状況が発生するはずです。

答え1

これはあなたが言及したのと同じ問題です。ローカルシェルは1つのレイヤーの引用符を削除します。これはどうしたの?

初期コード

ssh localhost sh -c 'echo "0=$0 1=$1"' arg1 arg2 arg3

ローカルシェル拡張後、コマンド実行前

ssh localhost sh -c echo "0=$0 1=$1" arg1 arg2 arg3
#                   ^^^^^^^^^^^^^^^^ a single token
#             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ passed to the remote shell

シェル拡張後に実行する前にリモートシェルで

sh -c echo 0= 1= arg1 arg2 arg3
#          ^^^^^ a single token
#     ^^^^ argument for -c

getsは実行するコマンドにechoバインドされ、残りはパラメータです。sh -c

空白行が表示されます。

個人的には、sshその引数をリモートシェルに直接渡す方法を学び、リモートシェルで実行されます。だから私は実行のためにその部分がそのままリモートシェルに渡されることをssh思い出させるこのようなコマンドを書く傾向があります。some command line…私が直接入力したように:

ssh remoteHost 'some command line…'

(ローカル評価を避けるために行を一重引用符で囲み、ローカル変数を挿入するには二重引用符を使用してください。)


そして、実際には、ルートファイルを別のシステムにコピーするためにsshコマンドを取得しようとしていると言います。

file=/etc/hosts
ssh -n host1 "scp -p '$file' host2:'/path/to/destination'"

あるいは、ファイル名は安全であり、ローカルクライアントとhost1from toのhost1間にルート同等性があると仮定しますhost2

ssh -n root@host1 scp -p /etc/hosts host2:/etc/hosts

現代的なものはscpさらに簡素化できます。

scp -OR -p root@host1:/etc/hosts root@host2:/etc/

答え2

-vコマンドに追加すると、ssh実行中のアクションが表示されます。

debug1: Sending command: sh -c echo "0=$0 1=$1" arg1 arg2 arg3

もちろん、コマンドをローカルで実行すると、実行後0番目の引数になってshから空の出力行だけが得られます。shecho"0=$0 1=$1"

前に以下を追加すると、true;これが発生します。

debug1: Sending command: sh -c true; echo "0=$0 1=$1" arg1 arg2 arg3

sh実行してみてくださいtrue。その後、対応するechoパラメータを出力します。

0=bash 1= arg1 arg2 arg3

sh -c 'echo "0=$0 1=$1"' arg1 arg2 arg3おそらくあなたが望むのは反対側に走ることです。リモートシェルがコマンド全体を受け取るようにコマンド全体を引用する必要があります。

ssh localhost "sh -c 'echo \"0=\$0 1=\$1\"' arg1 arg2 arg3"

出力:

0=arg1 1=arg2

printfローカル側にGNUがある場合は、それを使用してリモート側に合わせてフォーマットすることで、コマンド文字列を読みやすくすることができます。

command='echo "0=$0 1=$1"'
ssh localhost "sh -c $(printf %q "$command") arg1 arg2 arg3"

関連情報