如何将空数组元素设置为零?

如何将空数组元素设置为零?

我正在编写一个脚本,将命令的结果发送到输出数组。它涉及检查服务器的日志并检索其大小,但是在某些情况下,服务器具有故障转移主机。在这些情况下,我需要脚本来检查两台主机并返回值。我遇到的问题是,如果任何输出数组元素为空(意味着服务器中不存在要检查的文件,仅在其各自的回显显示中返回一个空格),则会导致数组索引发生变化。这意味着辅助主机阵列集中应包含的内容会撞到主要主机阵列集中。相反,我希望将这些空索引存储为 0 作为占位符,以防止发生移位。这是索引偏移明显的地方:

echo The primary overall log value is ${output[0]}.
echo The primary obs log value is ${output[2]}.    
echo The primary tracks log value is ${output[4]}.  
echo
echo The secondary overall log value is ${output[6]}.
echo The secondary overall log value is ${output[8]}.
echo The secondary overall log value is ${output[10]}.

例如,如果输出[2]和[4]为空,则输出[6]将向上移动到与输出[2]相对应的行。我尝试过这个解决方案,但没有运气:

  s=0

  for x in "${output[@]}"
     do(
     x=
        if [[ -z $x ]];
        then(
        x=0
        echo $x)
        else echo
        fi
     s=s+1)
 done

所有这一切都是在输出回波发生之前吐出零,并且不会针对任何索引移位进行调整。

注意:这是输出数组的来源,以及在其下方进行修复的尝试:

for h in "${host[@]}"
do
    for path in "${paths[@]}"
    do
            output+=( $(ssh $h du -sh $path) )
            for x in "${!output[@]}";
            do(
                    if [[ -z "${output[$x]}" ]];
                    then output[$x]=0;
                    fi;
            )
            done

    done
done

其中主机和路径是已经定义的数组。我还注意到,该脚本在只有一台主机可供访问的情况下运行良好,并且那里的数组索引没有问题。

答案1

例如,如果输出[2]和[4]为空,则输出[6]将向上移动到与输出[2]相对应的行。

在这种情况下,您实际上并没有用空值来代替 2 和 4,只是您的值比您预期的要少。

考虑数组分配:

array1=(a b c d)
array2=(A D)

第一个设置array1[0]aarray1[1]tob等。第二个设置array2[0]Aarray2[1]to D。无法知道A和之间是否应该有空值D。他们需要明确地出现在作业中:

array2=(A "" "" D)

您可能以其他方式填充数组output,但由于您没有显示它是如何完成的,因此无法对其进行评论。您可能遇到与上面类似的情况:“空”值根本不被填充数组的任何值视为值output

如果您从扩展中分配给数组并依赖分词,则无法真正避免这种情况。 (即使IFS只包含换行符,它也会将连续的空换行符折叠为一个,删除空行)。如果您使用mapfile,则默认情况下空行应显示为数组元素。


在任何情况下,将空数组元素置零的循环都不起作用,因为您根本没有在循环内分配给数组,即使分配了,循环体也会在子shell中运行(如括号(...)),因此任何赋值都不会发生在循环体之外。

您不能真正使用 afor x in "${output[@]}"来有效地修改数组元素,因为x仅获取数组值的副本,修改它不会更改原始值。您需要循环数组索引才能指向数组:

somearray=(1 "" "" 4)
for i in "${!somearray[@]}"; do
    if [[ -z "${somearray[$i]}" ]]; then
        somearray[$i]=0;
    fi;
done
echo "${somearray[@]}"

印刷1 0 0 4


在您添加的示例代码中,分配output+=( $(ssh $h du -sh $path) )不会添加任何空元素。缺失的路径将从数组中省略。首先考虑一下,du $path 如果路径不存在,则不会打印任何内容。 (除了错误之外,它会发送到 stderr,并且不会被命令替换捕获。)此外,即使它确实打印了空行(或空格/制表符),分词也会删除连续的空格。

尝试例如array=( $( printf "foo\n\nbar\n" ) ),它创建一个包含两个元素的数组。

此外,替换循环中的括号启动一个子shell,因此对数组的任何修改只会在该子shell内生效。一般来说,你想要用括号将 shell 命令分组,除非您知道您特别需要一个子 shell。

您可以在命令替换 ( "$(ssh ... du)") 两边加上引号,以确保您得到的正是一个字符串,但您可能希望将大小与路径名分开。

尝试这样的方法将路径及其大小收集到单个数组中:

for host in "${hosts[@]}"; do
    for path in "${paths[@]}"; do
        output="$(ssh "$host" du -sh "$path")"
        size="${output%%$'\t'*}"           # needs Bash/ksh/zsh
        size="${size:-0}"
        sizes+=( "$size" "$host:$path"  )
    done
done

现在,每个偶数数组元素都包含一个大小,每个奇数数组元素都包含相应的主机名和路径,有点像分割 的输出du会导致的结果。 的两个参数扩展outputsize删除制表符后的所有内容,然后将大小替换为如果为空则为零。

或者,你可以构建关联数组,由主机+路径索引:

declare -A array
...
    array["$host:$path"]=$size

相关内容