非対話型ランタイムbashテストエラーの結果

非対話型ランタイムbashテストエラーの結果

再起動が必要なときにスクリプトを介してUbuntuサーバーを再起動してみました。

Bashで非対話型コマンドでテストを実行すると、ファイルが/var/run/reboot-required存在しても再起動が必要ないという結果が得られます。

usera@client:~$ ssh server02 bash -c 'test -f /var/run/reboot-required && echo sudo reboot || echo "$(hostname): no reboot required"'
server02: no reboot required

SSHを介して同じサーバーにログインして手動でテストを実行すると、正しい結果が得られますsudo reboot

usera@client:~$ ssh server02
Last login: Tue Jun 14 08:03:00 2022 from 146.140.16.1
usera@server02:~$ test -f /var/run/reboot-required && echo sudo reboot || echo "$(hostname): no reboot required"
sudo reboot
usera@server02:~$ bash -c 'test -f /var/run/reboot-required && echo sudo reboot || echo "$(hostname): no reboot required"'
sudo reboot

正しい結果を得るために何を変更する必要がありますか?

答え1

私はこれがSSHがコマンドを渡す方法によるものであると確信しています。ワイヤーリモート側では、インポートされたすべての引数を連結してスペースで連結し、リモートシェルにそれを解析して実行させることでこれを行います。

考えてみてください。ssh somehost ls -l /etc/passwdと同じように動作します。シェルコマンドラインから直接実行するのとは異なり、存在しない奇妙な名前のコマンドにエラーは表示されませんssh somehost 'ls -l /etc/passwd''ls -l /etc/passwd'

だから、

ssh somehost bash -c 'test whatever || echo no'

コマンドラインで

bash -c test whatever || echo no

Bashはに設定されたtestコマンドの実行を開始します。引数なしで失敗するため実行されます。次のことを試すこともできます。これはリモートホームディレクトリでのみ機能する必要があります。$0whatevertest|| echossh somehost bash -c 'ls -l /etc/passwd'ls

したがって、中間シェルを使用しないでください。

ssh server02 'test -f /etc/passwd && echo passwd exists || echo "$(hostname): passwd does not exist"'

または、次のことを行うこともできます。

ssh server02 'bash -c "test -f /etc/passwd && echo yes || echo \"\$(hostname): no\"'

ただし、別の引用符付き文字列を入れ子にして、その文字列が保持する拡張子を実行する最も内側のシェルであることを確認したい場合は、引用符がトリッキーになります。リモートで両方のシェルが同じ結果を提供するので、それは重要ではありませんが、$(hostname)より一般的な場合は参照地獄があります。このような複雑な状況では、リモートでファイルを生成し、そこからスクリプトを実行する方がはるかに簡単になります。

これは基本的に次の質問です。引用された SSH コマンド

また、見ることができますSSH経由で `sh -c`スクリプトを実行する(パラメータを安全かつ正常に渡す)複雑なコマンドを渡すためのその他のソリューションリモートユーザーのログインシェルを知らず、SSHを介して任意の単純なコマンドをどのように実行できますか?これは、潜在的に未知のリモートログインシェルに関連するまれなケースです。

関連情報