リモートシステムにPS1を追加しようとしています/etc/profile
。現在、この文字列を70台以上のサーバーに追加する必要があるため、ssh
このPS1文字列をすべてのサーバーに追加します。しかし、PS1を送信しようとするとハングし、コマンドを強制終了する必要があります。
これはコマンドです
ssh -v admin@remserv "sed '/002/a \ PS1=" \[\e[31m\]\n------------------------------------------------------------------------------------------------------------------------------ \n\n[\u@\h \W]\\$ - \# \[\e[0m\] " /etc/profile' "
ここで何が欠けているのでしょうか?
提案に基づいてコマンドを編集しました
> ssh -vt admin@remserv printf "%s\n" "sudo sed -i.bak '/002/a \
> PS1="
> '\[\e[31m\']'\'n------------------------------------------------------------------------------------------------------------------------------ '\'n'\'n'[\u@\h \W']'\\'$ - '\'# '\[\e[0m\'] " /etc/profile' "
答え1
ssh ... "sed '/002/a \ PS1=" \[\e[31m\]\n--...- \# \[\e[0m\] " /etc/profile' "
^ ^ ^ ^
引用符で囲まれた文字列内に引用符で囲まれていない二重引用符が 2 つありますが、これらはシェルによって削除されます (ssh 接続のローカル側)。また、内側の一重引用符はコマンドsed
とファイル名の両方にまたがっているように見えるため、リモート シェルが引用符の処理を行った後、sed
で 1 つの引数を取得します/002/a \ ... /etc/profile
。これは実際にイメージ内の ssh の出力に表示されます。
(まあ、少なくとも頭に浮かぶのはそういうことです。二重引用符の問題は、少なくとも十分なコーヒーを飲まないと私の脳ではうまく機能しません。)
次のようなコマンドを実行することでデバッグできるはずです。
ssh somewhere printf '"%s\n"' "sed '/002/... /etc/profile' "
はprintf
、取得した引数を 1 行に 1 つずつ出力します。これにより、文字列が実際に分割される場所がわかりやすくなります (echo はスペースで結合されるため、foo
, bar
, は と同じように見えますfoo bar
)。フォーマット文字列を二重引用符で囲むと、リモートに対してバックスラッシュがそのまま保持されます。
答え2
OK、'\'文字を使ってこれを解決します
正しいコマンド
for i in `cat serverslist`; do ssh -t admin@$i "sudo sed -i.bak '/002/a \ PS1="\" '\\'['\\'e[31m'\\']'\\n'------------------------------------------------------------------------------------------------------------------------------ '\\'n'\\'n['\\'u@'\\'h '\(''\\'W'\)']'\\''\\'$ - '\\'# '\\'['\\'e[0m'\\'] \"" ' /etc/profile " ;done ;