SSHを使用してさまざまなサーバーからいくつかのデータをキャプチャし、特定の条件でいくつかのコマンドを実行したいと思います。
私はしたくありません:
if ssh $host test -f /file; then
# If file exists
var=$(ssh $host long pipeline)
else
# if it doesn't
var=$(ssh $host another long pipeline)
fi
なぜなら、プロセスが長くなるからです。リモートコンピュータでif elseを実行したいです。
いくつかの方法を試しましたが、成功しませんでした。
var=$(ssh $host if [ -f /file ]\; then long pipeline1 \; else long pipeline2 \; fi)
ベース回答、動作しますが、パイプライン1の最後のコマンドは、そのコマンドとelse
パイプライン2の残りの部分を引数と見なします。
command: can't read else: No such file or directory
...
command: can't read fi: No such file or directory
それからこれを試しました。
var=$(ssh $host test -f /file \&\& pipeline1 \|\| pipeline2)
同様に、pipeline1の最後のコマンドは||
その引数と見なされます。
私も以下で試しました(これ)、ランニング:
do_this () {
if [ -f /file ]; then
pipeline1
else
pipeline2
fi
}
var=$(ssh $host "$(set); do_this")
しかし、私の変数には影響しませんが、私のスクリプトは見苦しい不要なエラーメッセージを出力します。
bash: line 1: BASHOPTS: readonly variable
bash: line 8: BASH_VERSINFO: readonly variable
bash: line 24: EUID: readonly variable
bash: line 71: PPID: readonly variable
bash: line 82: SHELLOPTS: readonly variable
bash: line 92: UID: readonly variable
どんな提案がありますか?
修正する
私のパイプラインが何であるかを含める必要があると思います。基本的に、それはテキスト処理バンドルです。
cat file | grep "something" | sed 's/.*="\(.*\)"/\1/' | tr ' ' '-'
の回答に基づいてJechiselつまり、コマンドを一重引用符で囲む必要があります。
var=$(ssh $host 'if [ -f /file ]; then cat file | grep "something" | sed 's/.*="\(.*\)"/\1/' | tr ' ' '-' ; else cat otherfile | ... ; fi'
私は持っていますtr: invalid option -- ';'
。パラメータtr
として使用されます。;
動作方法は次のとおりですheredoc
。
var=$(ssh $host <<-EOF
if [ -f file ]; then
pipeline1
else
pipeline2
fi
EOF
)
しかし、sedで使用されている正規表現はvimの色を損なうでしょう。heredoc
今はこの答えを受け入れます。
アップデート2:私の質問は重複していないようです。sshpassの複数のコマンド、私の状況はより具体的で、他のスレッドは一般的に尋ねました。
答え1
存在する:
ssh host code
ssh
実際に引数として渡したコードを解釈するために、シェル(ターゲットユーザーのログインシェル)を実行します。複数の引数が指定されている場合、sshは引数をスペースで連結し、ユーザーのログインシェルにhost
それを再解釈させます。
一般的に言えば、合格したい一つ単一のコード引数を選択しssh
、ローカルシェルが拡張されないように単一引用符で囲む必要があります。
リモートユーザーのログインシェルがBourne / POSIXに似ていることがわかっている場合は、次のことを行う必要があります。
var=$(ssh "$host" '
if [ -f /file ]; then
pipeline1
else
pipeline2
fi'
)
リモートで解釈するコードに一重引用符を含める必要がある場合は、それらを挿入する必要があります'\''
(一重引用符の保持、引用符付き(バックスラッシュを使用)一重引用符の挿入、一重引用符の再入力)。
リモートユーザーのシェルを保護せずに標準入力を介してリモートコマンドにデータを渡す必要がない場合(そしてSSH接続以外にリダイレクトされない限り、リモートコマンドは標準入力から読み取られない)、次のことができます。
ssh "$host" sh << 'EOF'
if [ -f /file ]; then
pipeline1
else
pipeline2
fi
EOF
最初のトピックを参照して、EOF
このドキュメントでローカルシェルが拡張されないようにします。sh
スクリプトを書くために使用する構文を知るために、標準入力のコードを解釈するために明示的な呼び出しを行います。
このアプローチでは、単一引用符をエスケープする必要もありません。
あなたの
cat file | grep "something" | sed 's/.*="\(.*\)"/\1/' | tr ' ' '-'
次のように書くことができます:
<file sed '/something/!d; s/.*="\(.*\)"/\1/; y/ /-/'
だからこれは私たちに次のことを与えます:
ssh "$host" '
file=/path/to/some/file
otherfile=/path/to/some/other/file
if [ -f "$file" ]; then
<"$file" sed '\''/something/!d; s/.*="\(.*\)"/\1/; y/ /-/'\''
else
<"$otherfile" ...
fi'
(リモートユーザーのログインシェルがBourne / POSIXのような構文と異なる構文を持つcsh、tcsh、fish、rc、es、akangaの場合、このコマンドは機能しません。)
または:
ssh "$host" sh << 'EOF'
file=/path/to/some/file
otherfile=/path/to/some/other/file
if [ -f "$file" ]; then
<"$file" sed '/something/!d; s/.*="\(.*\)"/\1/; y/ /-/'
else
<"$otherfile" ...
fi
EOF
答え2
数年前も同様のことをしましたが、こうしました。
まず、終了ステータスをテストしてください。
ssh -t remoteuser@lremotehost 'if [[ -e /etc/fstabs ]]; then exit 0; else exit 127; fi' >/dev/null 2>&1
終了ステータスを確認してください。
echo $?
出力127
はない/etc/fstabs
ので/etc/fstab
これで、末尾がないことを確認する/etc/fstabs
ように変更します。/etc/fstab
s
ssh -t remoteuser@lremotehost 'if [[ -e /etc/fstab ]]; then exit 0; else exit 127; fi' >/dev/null 2>&1
終了ステータスをもう一度確認してください。
echo $?
出力はリモートシステムに0
出力があるためです。/etc/fstab
その後、変数に入れて終了ステータスを確認し、それに基づいてスクリプトを実行します。また、終了ステータスを変数に保存します。
var=$(ssh -t remoteuse@remotehost 'if [[ -e /etc/fstabs ]]; then exit 0; else exit 127; fi; exec bash -li' >/dev/null 2>&1); pid=$?
case $pid in
0) echo 'good!';;
*) echo 'bad!' >&2;;
esac
これが私がこの状況で生き残った方法です。完璧な解決策とは言えませんが、確認してみてください。ただし、SSHキーをリモートホストに渡したため、SSH経由でログインしてもパスワードは確認されません。私も両方のコンピュータでログインシェルとしてbashを使用していますが、これは私が次exec bash -li
の理由です。