如何在 Unix 中进行索引到索引值的比较

问题描述

我有一个场景,我使用 array_2 [index] 值检查了 array_1 [index] 值。

我下面的代码就像一个魅力,但有什么不同的方法来实现相同的吗?

我正在寻找一种处理 2 个数组列表值并进行比较的独特方法, 用几行代码

我的代码

#!/bin/bash

array_1=(4 4 3)
array_2=(4 1 3)

i=''
j=''

count=0
for i in "${array_1[@]}"
do 
 i="cmd ${array_1[$count]}"
 j="cmd ${array_2[$count]}"
   
     if [ "$i" -eq "$j" ]
     then
           echo "${array_1[$count]} match with ${array_2[$count]}"
           count=$(( count + 1 ))        
     else 
           echo "${array_1[$count]} does not match with ${array_2[$count]}"
           exit 1
     fi 
      
done 

注意:使用 shellcheck.net 检查代码,未发现错误

如果两个数组有不同的值,下面是输出

array_1=(4 4 3)
array_2=(4 1 3)

输出

4 match with 4
4 does not match with 1

如果两个数组具有相同的值,则输出如下:

array_1=(4 4 3)
array_2=(4 4 3)

输出

4 match with 4
4 match with 4
3 match with 3

解决方法

与您最近的其他 shell 问题一样,您根本不应该在 shell 中执行此操作,但由于您似乎专注于这样做,这里是如何简单地执行您正在做的操作(减去确切的输出格式):>

$ cat tst.sh
#!/usr/bin/env bash

array_1=(4 4 3)
array_2=(4 1 3)

diff -y <(printf '%s\n' "${array_1[@]}") <(printf '%s\n' "${array_2[@]}")

$ ./tst.sh
4                                                               4
4                                                             | 1
3                                                               3

这里是如何在 shell 中编写问题中的代码(如果数组大小不同,现有代码将失败):

$ cat tst.sh
#!/usr/bin/env bash

array_1=(4 4 3)
array_2=(4 1 3)

size1=${#array_1[@]}
size2=${#array_2[@]}
if (( size1 > size2 )); then
    maxSize=$size1
else
    maxSize=$size2
fi

for (( i=0; i<maxSize; i++ )); do

     val1=${array_1[i]}
     val2=${array_2[i]}

     if [ "$val1" -eq "$val2" ]
     then
           echo "${array_1[$i]} match with ${array_2[$i]}"
     else
           echo "${array_1[$i]} does not match with ${array_2[$i]}"
           exit 1
     fi

done

$ ./tst.sh
4 match with 4
4 does not match with 1

但更好的方法是,假设您出于某种原因确实需要从 2 个 shell 数组开始:

$ cat tst.sh
#!/usr/bin/env bash

array_1=(4 4 3)
array_2=(4 1 3)

awk -v string_1="${array_1[*]}" -v string_2="${array_2[*]}" '
    BEGIN {
        size1 = split(string_1,array_1)
        size2 = split(string_2,array_2)

        maxSize = (size1 > size2 ? size1 : size2)

        for (i=1; i<=maxSize; i++) {
            val1 = array_1[i]
            val2 = array_2[i]

            if ( val1 == val2 ) {
                printf "%s match with %s\n",array_1[i],array_2[i]
            }
            else {
                printf "%s does not match with %s\n",array_2[i]
                exit 1
            }
        }
    }
'

$ ./tst.sh
4 match with 4
4 does not match with 1
,

您在问题中添加了 awk

使用 awk,您可以:

awk 'FNR==NR{x[FNR]=$1; next}
     x[FNR]==$1{print x[FNR] " match with " $1; next}
     {print x[FNR] " does not match with " $1}
     ' <(printf "%s\n" "${array_1[@]}") <(printf "%s\n" "${array_2[@]}")

或者使用 pasteawk,您可以:

paste <(printf "%s\n" "${array_1[@]}") <(printf "%s\n" "${array_2[@]}") | awk '
$1==$2{print $1 " match with " $2; next}
{print $1 " does not match with " $2}'

打印(使用示例中的两个数组):

4 match with 4
4 does not match with 1
3 match with 3

如果您想在第一次不匹配后退出,只需在 exit 后添加 print

awk 'FNR==NR{x[FNR]=$1; next}
     x[FNR]==$1{print x[FNR] " match with " $1; next}
     {print x[FNR] " does not match with " $1; exit 1}
     ' <(printf "%s\n" "${array_1[@]}") <(printf "%s\n" "${array_2[@]}")

说明

printf "%s\n" "${array_1[@]}" 的构造将 array_1 的输出创建为由 \n 分隔的字符串:

printf "%s\n" "${array_1[@]}"
4
4
3

结构:

cmdX <(cmdY)

执行以下操作:

  1. cmdY
  2. 的标准输出在 shell 中创建一个类似匿名文件的 fifo
  3. 将文件名提供给类似文件的输出到 cmdX 作为参数,然后作为文件读取。

paste 接受两个类似文件的输入并创建一个两列的单输出:

paste <(printf "%s\n" "${array_1[@]}") <(printf "%s\n" "${array_2[@]}") 
4   4
4   1
3   3

一旦您将数组并排放置或将它们视为两个文件,那么将两者与 awk diff comm perlruby 进行比较是微不足道的。