如何通过 SSH 传递复杂的 shell 命令以远程执行?我的抛出语法错误或在本地被解释!

use*_*225 4 ssh command-line bash scripts

我有一个这样的命令,它告诉我系统的磁盘是否已满(>=70% 已满):

if [[ -n df -PTh|column -t|awk '{print $6 $7}'|awk -F"%" '{printf "%-9s %-5s\n",$1,$2}'|grep -v -e "Use" -e "Mounted"|awk '$1>70{printf "%-9s %-5s\n",$1,$2}' ]]; then echo "not present"; else echo ">70 is present"; fi
Run Code Online (Sandbox Code Playgroud)

我想使用 SSH 在远程服务器上执行上述命令。就像是:

ssh remoteserver "if [[ -n df -PTh|column -t|awk '{print $6 $7}'|awk -F"%" '{printf "%-9s %-5s\n",$1,$2}'|grep -v -e "Use" -e "Mounted"|awk '$1>70{printf "%-9s %-5s\n",$1,$2}' ]]; then echo "not present"; else echo ">70 is present"; fi"
Run Code Online (Sandbox Code Playgroud)

但是当我尝试这样做时,出现以下错误:

HOST: remoteserver bash: -c: line 0: syntax error in conditional expression bash: -c: line 0: syntax error near /home'
bash: -c: line 0:if [[ -n 92 /home'
Run Code Online (Sandbox Code Playgroud)

Oli*_*Oli 7

首先,我会将 awk/grep/awk/grep/awk/grep/etc 语句的战争罪行减少到:

df | awk '$5~/([7-9]|10)[0-9]/'
Run Code Online (Sandbox Code Playgroud)

它可以完成您检查输出所需的一切。如果你真的需要漂亮的输出,你可以{print ...}awk语句中添加一个子句,但鉴于你只是检查是否有输出,让我们对此合理吗?。

我们还可以缩短 if/else。我也更正了方向——你的方向相反。整个命令现在看起来像:

[[ -n $(df | awk '$5~/([7-9]|10)[0-9]/') ]] && echo 'ACHTUNG!' || echo 'No >=70s'
Run Code Online (Sandbox Code Playgroud)

我想你会同意这只是稍微更有启发性。

现在您可能现在可以手动转义它并将其包装在 a 中,bash -c "..."但这有什么乐趣呢?相反,让我们将命令保存到本地文件(比如 commands.txt)中,您可以像这样将其发送到服务器:

ssh user@host $(<commands.txt)
Run Code Online (Sandbox Code Playgroud)

你可以把它留在那里。您实际上可以将原始命令的工作版本放入其中并将其发送过来。这东西非常健壮......但我们不想这样做......当我们可以更聪明(和作弊)使用命令并取消if括号(这是导致转义问题的事情)时不是)。

我们目前正在df远程运行并远程处理它。我们不需要那样做。我们可以让ssh运行df然后在本地处理输出。这立即解决了转义问题,但我们目前被困在逻辑[[括号中]],这会使重写有点难看:

[[ -n $(ssh user@host df | awk '$5~/([7-9]|10)[0-9]/') ]] && .......
Run Code Online (Sandbox Code Playgroud)

哎呀。
我们比那更好。
与在我们之前踩踏的猴子和猿不同,我们有退出代码。

当某些东西完成运行时,它可以返回一个代码。这些代码意味着各种各样的东西,但一般来说0意味着“我完全按照我的设计做了”,更高的意味着“我做得不好,鲍斯”。

条件钩子喜欢&&||查看输入它们的退出代码来决定是否运行。在我们的例子中,这意味着如果我们告诉awk以非零方式退出,我们可以控制代码流:

ssh user@host df | awk '$5~/([7-9]|10)[0-9]/ {exit 1}' && echo 'No >=70s' || echo 'ACHTUNG!'
Run Code Online (Sandbox Code Playgroud)

这也意味着它会在检测到第一个 >=70 值后立即退出。如果您有数百万个驱动器,与其他领先品牌的脚本相比,这可以为您节省几秒钟的时间。所以是的,只是为了重申这个最终版本中发生的事情:

  1. 我们正在连接到服务器并df远程运行
  2. 输出通过管道返回到本地实例 awk
  3. awk 查看第五列是否匹配正则表达式以匹配 70-100
  4. 如果是这样,它退出代码1和||代码执行(那里一个驱动器中使用超过70%)
  5. 如果不是,则退出代码 0 并&&执行代码。

在以前的修订版中,我也NR>1检查了awk语句,但鉴于我们明确检查了第五列的值(并且它有一个数字可以工作),我们也可以安全地省略它。