arrays - 无法在 Bash Shell 脚本中打印整个数组

标签 arrays linux bash shell

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

我将 top 与“-p”选项一起使用,为它提供一个以逗号分隔的 PID 值列表。在这种模式下使用时,一次只能查询 20 个 PID,因此我不得不想出一种方法来处理要查询超过 20 个 PID 的情况。我正在拆分传递给下面函数的 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 个放入 $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 tag wiki对于创建小型、简化的测试用例有额外的建议。这是显示您的问题的最小版本:

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

预期:值:foo bar。实际值:值: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

关于arrays - 无法在 Bash Shell 脚本中打印整个数组,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22821643/

相关文章:

linux - 如何在ubuntu server 14.04 LTS 上配置多个网卡并连接路由器?

c - 默认选项 GCC

java - 如何从命令行添加外部 Jar 并使用文件的完整路径来编译和执行 Java?

bash - 重定向 cron 作业的输出

bash - Docker容器中的Bash脚本意外 “permission denied”

javascript - 如何使用 keydown 函数制作 JavaScript 待办事项列表

java - 需要 java/file IO 方面的帮助

python - 从 optparse python 获取最后一个参数

c# - MySQL 数据对于 LONGBLOB 上出现的列来说太长

C 从文件读取输入到二维数组 - 每行的行数可变