繁体   English   中英

无法在Bash Shell脚本中打印整个阵列

[英]Cannot print entire array in Bash Shell script

我已经编写了一个Shell脚本来获取特定进程名称的PID(例如pgrep pythonpgrep java ),然后使用top来获取这些PID的当前CPU和内存使用情况。

我将top与'-p'选项一起使用,以给它一个逗号分隔的PID值列表。 在这种模式下使用它时,一次只能查询20个PID,所以我不得不想出一种方法来处理要查询的PID超过20个的情况。 我正在拆分传递给以下函数的PID列表,并“分派”多个顶部命令以查询资源:

# $1 = List of PIDs to query
jobID=0
for pid in $1; do
    if [ -z $pidsToQuery ]; then
        pidsToQuery="$pid"
    else
        pidsToQuery="$pidsToQuery,$pid"
    fi
    pidsProcessed=$(($pidsProcessed+1))
    if [ $(($pidsProcessed%20)) -eq 0 ]; then
        debugLog "DESPATCHED QUERY ($jobID): top -bn 1 -p $pidsToQuery | grep \"^ \" | awk '{print \$9,\$10}' | grep -o '.*[0-9].*' | sed ':a;N;\$!ba;s/\n/ /g'"
        resourceUsage[$jobID]=`top -bn 1 -p "$pidsToQuery" | grep "^ " | awk '{print $9,$10}' | grep -o '.*[0-9].*' | sed ':a;N;$!ba;s/\n/ /g'`
        jobID=$(($jobID+1))
        pidsToQuery=""
    fi
done
resourceUsage[$jobID]=`top -bn 1 -p "$pidsToQuery" | grep "^ " | awk '{print $9,$10}' | grep -o '.*[0-9].*' | sed ':a;N;$!ba;s/\n/ /g'`

top命令将以以下格式(CPU,MEM,CPU,MEM等)返回每个PID的CPU和内存使用率:

13 31.5 23 22.4 55 10.1

问题出在resourceUsage数组上。 假设我要处理25个PID,上面的代码会将前20个PID的结果放入$resourceUsage[0] ,将最后5个PID的结果放入$resourceUsage[1] 我已经对此进行了测试,可以看到每个数组元素都有从顶部返回的值列表。

下一点是我遇到的困难。 每当我想打印或使用整个数组的一组值时,我都会使用${resourceUsage[@]} 每当我在此脚本的上下文中使用该命令时,我只会获取元素0的数据。 我在下面的脚本中分离了此功能,以进行尝试和调试。 我也在这里看到了相同的问题(数据输出到debug.log中与脚本相同的目录中):

#!/bin/bash

pidList="1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25"

function quickTest() {
    for ((i=0; i<=1; i++)); do
        resourceUsage[$i]=`echo "$i"`
    done

    echo "${resourceUsage[0]}"
    echo "${resourceUsage[1]}"
    echo "${resourceUsage[@]}"
}


function debugLog() {
    debugLogging=1
    if [ $debugLogging -eq 1 ]; then
        currentTime=$(getCurrentTime 1)
        echo "$currentTime - $1" >> debug.log
    fi
}

function getCurrentTime() {
    if [ $1 -eq 0 ]; then
        echo `date +%s`
    elif [ $1 -eq 1 ]; then
        echo `date`
    fi
}

jobID=0

for pid in $pidList; do
    if [ -z $pidsToQuery ]; then
        pidsToQuery="$pid"
    else
        pidsToQuery="$pidsToQuery,$pid"
    fi
    pidsProcessed=$(($pidsProcessed+1))
    if [ $(($pidsProcessed%20)) -eq 0 ]; then
        debugLog "DESPATCHED QUERY ($jobID): top -bn 1 -p $pidsToQuery | grep \"^ \" | awk '{print \$9,\$10}' | grep -o '.*[0-9].*' | sed ':a;N;\$!ba;s/\n/ /g'"
        resourceUsage[$jobID]=`echo "10 10.5 11 11.5 12 12.5 13 13.5"`
        debugLog "Resource Usage [$jobID]: ${resourceUsage[$jobID]}"
        jobID=$(($jobID+1))
        pidsToQuery=""
    fi
done
#echo "Dispatched job: $pidsToQuery"
debugLog "DESPATCHED QUERY ($jobID): top -bn 1 -p $pidsToQuery | grep \"^ \" | awk '{print \$9,\$10}' | grep -o '.*[0-9].*' | sed ':a;N;\$!ba;s/\n/ /g'"
resourceUsage[$jobID]=`echo "14 14.5 15 15.5"`
debugLog "Resource Usage [$jobID]: ${resourceUsage[$jobID]}"
memUsageInt=0
memUsageDec=0
cpuUsage=0
i=1
debugLog "Row 0: ${resourceUsage[0]}"
debugLog "Row 1: ${resourceUsage[1]}"
debugLog "All resource usage results: ${resourceUsage[@]}"
for val in ${resourceUsage[@]}; do
    resourceType=$(($i%2))
    if [ $resourceType -eq 0 ]; then
        debugLog "MEM RAW: $val"
        memUsageInt=$(($memUsageInt+$(echo $val | cut -d '.' -f 1)))
        memUsageDec=$(($memUsageDec+$(echo $val | cut -d '.' -f 2)))
        debugLog "   MEM INT: $memUsageInt"
        debugLog "   MEM DEC: $memUsageDec"
    elif [ $resourceType -ne 0 ]; then
        debugLog "CPU RAW: $val"
        cpuUsage=$(($cpuUsage+$val))
        debugLog "CPU TOT: $cpuUsage"
    fi
    i=$(($i+1))
done
debugLog "$MEM DEC FINAL: $memUsageDec (pre)"
memUsageDec=$(($memUsageDec/10))
debugLog "$MEM DEC FINAL: $memUsageDec (post)"
memUsage=$(($memUsageDec+$memUsageInt))
debugLog "MEM USAGE: $memUsage"
debugLog "CPU USAGE: $cpuUsage"
debugLog "MEM USAGE: $memUsage"
debugLog "PROCESSED VALS: $cpuUsage,$memUsage"
echo "$cpuUsage,$memUsage"

我真的被困在这里,因为之前我已经在Bash Shell中毫无问题地打印了整个数组。 我什至在shell控制台中重复了几行,在这里可以正常工作:

listOfValues[0]="1 2 3 4"
listOfValues[1]="5 6 7 8"
echo "${listOfValues[@]}"

我是否缺少一些显而易见的东西? 任何帮助将不胜感激!

提前致谢! :)

欢迎使用StackOverflow,并感谢您提供测试用例! bash标签Wiki提供了有关创建小型简化测试用例的其他建议。 这是显示您的问题的最低版本:

log() {
  echo "$1"
}
array=(foo bar)
log "Values: ${array[@]}"

预期Values: foo bar 实际: Values: foo

发生这种情况是因为${array[@]}用引号引起来,并且变成了多个参数。 对于$@同样如此,为简便起见,让我们考虑一下:

假设$1foo$2bar

  • 单个参数"$@" (用引号引起来)等效于两个参数"foo" "bar"
  • "Values: $@"等效于两个参数"Values: foo" "bar"

由于您的日志语句将忽略第一个参数之后的所有参数,因此不会显示任何参数。 echo不会忽略它们,而是将所有参数以空格分开打印,这就是为什么它看起来可以交互工作的原因。

这与${array[*]}$* ,它们与$@完全一样,除了引号不是魔术,并且不会变成多个参数。

  • "$*"等效于"foo bar"
  • "Values: $*"等效于"Values: foo bar"

换句话说:如果要将数组中的元素合并为单个字符串,请使用* 如果要将数组中的所有元素添加为单独的字符串,请使用@

这是测试用例的固定版本:

log() {
  echo "$1"        
}
array=(foo bar)
log "Values: ${array[*]}"

输出Values: foo bar

我将使用ps而不是top来获取所需的信息。 无论如何,您可能希望将每个进程的数据放在数组的单独元素中,而不是将每个元素的数据放入20个批中。 您可以使用while循环和进程替换来执行此操作。 我使用一些数组技术来简化进程ID的处理。

pid_array=(1 2 3 4 5 6 7 8 9 ... )
while (( ${#pid_array[@]} > 0 )); do
     printf -v pidsToQuery "%s," "${pid_array[@]:0:20}"
     pid_array=( "${pid_array[@]:20}" )

     while read cpu mem; do
         resourceUsage+=( "$cpu $mem" )
     done < <( top -bn -1 -p "${pidsToQuery%,}" ... )
done

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM