snmpget到bash数组的输出

时间:2022-04-11 05:53:06

Trying to get output from snmpget into an array in bash. The purpose is to query a SAN device for SNMP status. snmpget commandline is as follows

尝试从snmpget获取输出到bash中的数组中。目的是查询SAN设备的SNMP状态。snmpget命令行如下

# /usr/bin/snmpget -v2c -Oqv -c public nas.mynetwork.lcl .1.3.6.1.4.1.9804.3.1.1.2.1.30.0 .1.3.6.1.4.1.9804.3.1.1.2.1.39.0

And its output is like

它的输出是

"P4500G2"
"12 600GB SAS 3.0Gbps drives"

I intend to use this in a script so I made variables of the whole command line. Here's the script, sending its output to a new array variable and then looping through the array.

我打算在脚本中使用它,因此我创建了整个命令行的变量。这是脚本,将它的输出发送到一个新的数组变量,然后在数组中循环。

# Paths and options
SNMPGET='/usr/bin/snmpget'
SNMPOPTIONS='-v2c -Oqv -c public'
SNMPHOST='nas.mynetwork.lcl'
SNMPOID1='.1.3.6.1.4.1.9804.3.1.1.2.1.30.0'
SNMPOID2='.1.3.6.1.4.1.9804.3.1.1.2.1.39.0'

# Run the command, strip quotes and leave output in variable SNMPREPLY
SNMPREPLY=($($SNMPGET $SNMPOPTIONS $SNMPHOST $SNMPOID1 $SNMPOID2 | tr -d '"'))

# Check what's in the array
for index in ${SNMPREPLY[*]}
 do echo $index
done

Output from the above script is this

上面脚本的输出是这样的

P4500G2
12
600GB
SAS
3.0Gbps
drives

As you can see the quotes are properly gone as intended, but every word from the snmpget was put in a separate array item. This is not the purpose but to keep each output line as a separate array item.

正如您所看到的,引号按照预期正确地消失了,但是来自snmpget的每个单词都放在一个单独的数组项中。这不是目的,而是将每个输出行保持为一个单独的数组项。

Tried to look into the bash IFS variable but can not get it work no matter what.

尝试查看bash IFS变量,但无论如何都无法使其工作。

What am I doing wrong?

我做错了什么?

2 个解决方案

#1


0  

It's easier to read the output line by line and append it to the array, rather than trying to capture it all at once.

逐行读取输出并将其附加到数组中比一次捕获更容易。

while IFS= read -r line; do
    snmpreply+=( "$line" )
done < <($SNMPGET $SNMPOPTIONS $SNMPHOST $SNMPOID1 $SNMPOID2 | tr -d '"')

Here, we redirect standard input for the loop (and thus the read command) from a process substitution. The output of the command inside the <(...) is treated as if it were a file. It's similar to the use of a pipeline

在这里,我们将循环(以及read命令)的标准输入从进程替换中重定向。<(…)中命令的输出被视为文件。它类似于管道的使用。

snmp ... | while IFS= read -r line; do
   ...
done

except it ensures that the loop runs in the current shell, so that the array you build in the loop is still available once the loop exits.

除了它确保循环在当前shell中运行,这样在循环中构建的数组在循环退出后仍然可用。

(If you are using bash 4, you can replace the loop with the readarray command:

(如果使用bash 4,可以使用readarray命令替换循环:

# -t strips the newlines from each line
readarray -t snmpreply < <( $SNMPGET ... )

)

)

When iterating over the array, use @ instead of * and quote the expansion, to protect whitespace.

当迭代数组时,使用@而不是*并引用扩展,以保护空白。

for item in "${snmpreply[@]}"
 do echo "item"
done

A few other notes:

其他一些笔记:

  1. Don't use all-uppercase names for your variables; those are reserved.

    不要对变量使用全大写名称;这些都是保留的。

    snmpget='/usr/bin/snmpget'
    snmpoptions='-v2c -Oqv -c public'
    snmphost='nas.mynetwork.lcl'
    snmpoid1='.1.3.6.1.4.1.9804.3.1.1.2.1.30.0'
    snmpoid2='.1.3.6.1.4.1.9804.3.1.1.2.1.39.0'
    
  2. Use an array to store multiple options for a command. You can store all the arguments in the same array for ease of calling:

    使用数组存储命令的多个选项。可以将所有参数存储在同一个数组中,以便调用:

    snmpoptions=( -v2c -0qv -c public   # your original options
                  nas.mynetwork.lcl     # the host
                  .1.3.6.1.4.1.9804.3.1.1.2.1.30.0  # oid1
                  .1.3.6.1.4.1.9804.3.1.1.2.1.39.0  # oid2
                  )
    

    When calling the command, quote all parameter expansions:

    调用命令时,引用所有参数展开:

    "$snmpget" "${snpoptions[@]}"
    

#2


0  

IFS is the right way to go.

如果是正确的方法。

OIFS=$IFS
IFS=$'\n'
f() { echo "'P4500G2'"; echo "'12 600GB SAS 3.0Gbps drives'"; }
f
'P4500G2'
'12 600GB SAS 3.0Gbps drives'

a=($(f))
for i in ${a[*]}; do echo $i ; done
'P4500G2'
'12 600GB SAS 3.0Gbps drives'

IFS=$OIFS
for i in ${a[*]}; do echo $i ; done
'P4500G2'
'12
600GB
SAS
3.0Gbps
drives'

#1


0  

It's easier to read the output line by line and append it to the array, rather than trying to capture it all at once.

逐行读取输出并将其附加到数组中比一次捕获更容易。

while IFS= read -r line; do
    snmpreply+=( "$line" )
done < <($SNMPGET $SNMPOPTIONS $SNMPHOST $SNMPOID1 $SNMPOID2 | tr -d '"')

Here, we redirect standard input for the loop (and thus the read command) from a process substitution. The output of the command inside the <(...) is treated as if it were a file. It's similar to the use of a pipeline

在这里,我们将循环(以及read命令)的标准输入从进程替换中重定向。<(…)中命令的输出被视为文件。它类似于管道的使用。

snmp ... | while IFS= read -r line; do
   ...
done

except it ensures that the loop runs in the current shell, so that the array you build in the loop is still available once the loop exits.

除了它确保循环在当前shell中运行,这样在循环中构建的数组在循环退出后仍然可用。

(If you are using bash 4, you can replace the loop with the readarray command:

(如果使用bash 4,可以使用readarray命令替换循环:

# -t strips the newlines from each line
readarray -t snmpreply < <( $SNMPGET ... )

)

)

When iterating over the array, use @ instead of * and quote the expansion, to protect whitespace.

当迭代数组时,使用@而不是*并引用扩展,以保护空白。

for item in "${snmpreply[@]}"
 do echo "item"
done

A few other notes:

其他一些笔记:

  1. Don't use all-uppercase names for your variables; those are reserved.

    不要对变量使用全大写名称;这些都是保留的。

    snmpget='/usr/bin/snmpget'
    snmpoptions='-v2c -Oqv -c public'
    snmphost='nas.mynetwork.lcl'
    snmpoid1='.1.3.6.1.4.1.9804.3.1.1.2.1.30.0'
    snmpoid2='.1.3.6.1.4.1.9804.3.1.1.2.1.39.0'
    
  2. Use an array to store multiple options for a command. You can store all the arguments in the same array for ease of calling:

    使用数组存储命令的多个选项。可以将所有参数存储在同一个数组中,以便调用:

    snmpoptions=( -v2c -0qv -c public   # your original options
                  nas.mynetwork.lcl     # the host
                  .1.3.6.1.4.1.9804.3.1.1.2.1.30.0  # oid1
                  .1.3.6.1.4.1.9804.3.1.1.2.1.39.0  # oid2
                  )
    

    When calling the command, quote all parameter expansions:

    调用命令时,引用所有参数展开:

    "$snmpget" "${snpoptions[@]}"
    

#2


0  

IFS is the right way to go.

如果是正确的方法。

OIFS=$IFS
IFS=$'\n'
f() { echo "'P4500G2'"; echo "'12 600GB SAS 3.0Gbps drives'"; }
f
'P4500G2'
'12 600GB SAS 3.0Gbps drives'

a=($(f))
for i in ${a[*]}; do echo $i ; done
'P4500G2'
'12 600GB SAS 3.0Gbps drives'

IFS=$OIFS
for i in ${a[*]}; do echo $i ; done
'P4500G2'
'12
600GB
SAS
3.0Gbps
drives'