〜のように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'"
あるいは、ファイル名は安全であり、ローカルクライアントとhost1
from 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
から空の出力行だけが得られます。sh
echo
"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"