本文介绍了通过SSH执行存储在关联数组中的bash命令,存储结果的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

对于不相关的较大项目,我需要从本地系统或远程系统收集系统统计信息。由于我以任何一种方式收集相同的统计信息,因此通过将stats-collecting命令存储在Bash关联数组中来防止代码重复。

For a larger project that's not relevant, I need to collect system stats from the local system or a remote system. Since I'm collecting the same stats either way, I'm preventing code duplication by storing the stats-collecting commands in a Bash associative array.

declare -A stats_cmds
# Actually contains many more key:value pairs, similar style
stats_cmds=([total_ram]="$(free -m | awk '/^Mem:/{print $2}')")

我可以像这样收集本地系统统计信息:

I can collect local system stats like this:

get_local_system_stats()
{
    # Collect stats about local system
    complex_data_structure_that_doesnt_matter=${stats_cmds[total_ram]}
    # Many more similar calls here
}

我的脚本的前提是设置〜/ .ssh / config 使得 ssh $ SSH_HOSTNAME 无需任何用户输入即可工作。我想要这样的东西:

A precondition of my script is that ~/.ssh/config is setup such that ssh $SSH_HOSTNAME works without any user input. I would like something like this:

get_remote_system_stats()
{
    # Collect stats about remote system
    complex_data_structure_that_doesnt_matter=`ssh $SSH_HOSTNAME ${stats_cmds[total_ram]}`
}

我已经尝试过单引号,双引号,反引号等各种组合,这些组合我都可以想象得到。某些组合会导致stats命令执行得太早( bash:7986:未找到命令),其他组合会导致语法错误,其他组合会返回null(stats命令周围的单引号)但是没有一个可以在我的数据结构中存储正确的结果。

I've tried every combination of single quotes, double quotes, backticks and such that I can imagine. Some combinations result in the stats command getting executed too early (bash: 7986: command not found), others cause syntax errors, others return null (single quotes around the stats command) but none store the proper result in my data structure.

如何通过SSH在远程系统上评估存储在关联数组中的命令并将结果存储在本地脚本中的数据结构?

How can I evaluate a command, stored in an associative array, on a remote system via SSH and store the result in a data structure in my local script?

推荐答案

首先,我将建议一种对现有内容进行最小更改的方法实施。然后,我将展示一些与最佳做法更接近的东西。

First, I'm going to suggest an approach that makes minimal changes to your existing implementation. Then, I'm going to demonstrate something closer to best practices.

给出您现有的代码:

declare -A remote_stats_cmds
remote_stats_cmds=([total_ram]='free -m | awk '"'"'/^Mem:/{print $2}'"'"''
            [used_ram]='free -m | awk '"'"'/^Mem:/{print $3}'"'"''
            [free_ram]='free -m | awk '"'"'/^Mem:/{print $4}'"'"''
            [cpus]='nproc'
            [one_min_load]='uptime | awk -F'"'"'[a-z]:'"'"' '"'"'{print $2}'"'"' | awk -F "," '"'"'{print $1}'"'"' | tr -d " "'
            [five_min_load]='uptime | awk -F'"'"'[a-z]:'"'"' '"'"'{print $2}'"'"' | awk -F "," '"'"'{print $2}'"'"' | tr -d " "'
            [fifteen_min_load]='uptime | awk -F'"'"'[a-z]:'"'"' '"'"'{print $2}'"'"' | awk -F "," '"'"'{print $3}'"'"' | tr -d " "'
            [iowait]='cat /proc/stat | awk '"'"'NR==1 {print $6}'"'"''
            [steal_time]='cat /proc/stat | awk '"'"'NR==1 {print $9}'"'"'')

...一个人可以在本地进行如下评估:

...one can evaluate these locally as follows:

result=$(eval "${remote_stat_cmds[iowait]}")
echo "$result" # demonstrate value retrieved

...或远程如下:

...or remotely as follows:

result=$(ssh "$hostname" bash <<<"${remote_stat_cmds[iowait]}")
echo "$result" # demonstrate value retrieved

不需要单独的表格。

现在,让我们谈谈完全不同的事物做到这一点的方式:

Now, let's talk about an entirely different way to do this:

# no awful nested quoting by hand!
collect_total_ram() { free -m | awk '/^Mem:/ {print $2}'; }
collect_used_ram()  { free -m | awk '/^Mem:/ {print $3}'; }
collect_cpus()      { nproc; }

...然后在本地进行评估:

...and then, to evaluate locally:

result=$(collect_cpus)

。 ..or,或进行远程评估:

...or, to evaluate remotely:

result=$(ssh "$hostname" bash <<<"$(declare -f collect_cpus); collect_cpus")

...,或者使用以下命令迭代定义的函数 collect _ 前缀并执行以下两项操作:

...or, to iterate through defined functions with the collect_ prefix and do both of these things:

declare -A local_results
declare -A remote_results
while IFS= read -r funcname; do
  local_results["${funcname#collect_}"]=$("$funcname")
  remote_results["${funcname#collect_}"]=$(ssh "$hostname" bash <<<"$(declare -f "$funcname"); $funcname")
done < <(compgen -A function collect_)

...或者将所有项目收集到一个一次通过单个远程阵列,避免了额外的SSH往返而不是 eval 或在从远程系统接收到结果时冒安全风险:

...or, to collect all the items into a single remote array in one pass, avoiding extra SSH round-trips and not eval'ing or otherwise taking security risks with results received from the remote system:

remote_cmd=""
while IFS= read -r funcname; do
  remote_cmd+="$(declare -f "$funcname"); printf '%s\0' \"$funcname\" \"\$(\"$funcname\")\";"
done < <(compgen -A function collect_)

declare -A remote_results=( )
while IFS= read -r -d '' funcname && IFS= read -r -d '' result; do
  remote_results["${funcname#collect_}"]=$result
done < <(ssh "$hostname" bash <<<"$remote_cmd")

这篇关于通过SSH执行存储在关联数组中的bash命令,存储结果的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

08-23 06:38