BASH: compare two arrays with IF

3

I have the following problem:

I compare two arrays, the first is a file and the second array stores the previous data from the first array. The idea is that when comparing the arrays a repeated data is not inserted to perform the operation only once.

Contents of the file to be read:

11.11.11.1
22.22.22.2
11.11.11.1
33.33.33.3

Script content:

DATOS=( 'cat archivo ' )
CONT5=${#DATOS[@]}
A="1"
for i in "$DATOS"
do

for (( i=0 ; i<$CONT5 ; i=i+1 )); do
    for (( r=0; r<$CONT5; r=r+1 )); do
if [ -z "${LOG[r]}" ]; then
    echo "Vacío" > /dev/null
    else

        if [ "$DATOS[i]" == "$LOG[r]" ] ;   then
        echo "" > /dev/null 
        echo "${DATOS[i]} ES IGUAL A ${LOG[r]} "
        A="0"
        else
        echo "${DATOS[i]} NO ES ${LOG[r]}"
        fi

    done
        if [ $A -eq 1 ] ; then
        echo "Realizar operación"
        fi
fi

    LOG[$i]=${DATOS[i]}
    A="1"
done
done

The problem is that you compare " 11.11.11.1 " of $DATOS with " 11.11.11.1 " of $LOG and interpret it as different strings.

Any ideas?

Thanks

EDIT: After adding the line of alo Malbarez the result of the dump is as follows:

Realizar operación
0000000   2   2   .   2   2   .   2   2   .   2       N   O       E   S
        062 062 056 062 062 056 062 062 056 062 040 116 117 040 105 123
0000020       1   1   .   1   1   .   1   1   .   1  \n
        040 061 061 056 061 061 056 061 061 056 061 012
0000034
Realizar operación
0000000   1   1   .   1   1   .   1   1   .   1       N   O       E   S
        061 061 056 061 061 056 061 061 056 061 040 116 117 040 105 123
0000020       1   1   .   1   1   .   1   1   .   1  \n
        040 061 061 056 061 061 056 061 061 056 061 012
0000034
0000000   1   1   .   1   1   .   1   1   .   1       N   O       E   S
        061 061 056 061 061 056 061 061 056 061 040 116 117 040 105 123
0000020       2   2   .   2   2   .   2   2   .   2  \n
        040 062 062 056 062 062 056 062 062 056 062 012
0000034
Realizar operación
0000000   3   3   .   3   3   .   3   3   .   3       N   O       E   S
        063 063 056 063 063 056 063 063 056 063 040 116 117 040 105 123
0000020       1   1   .   1   1   .   1   1   .   1  \n
        040 061 061 056 061 061 056 061 061 056 061 012
0000034
0000000   3   3   .   3   3   .   3   3   .   3       N   O       E   S
        063 063 056 063 063 056 063 063 056 063 040 116 117 040 105 123
0000020       2   2   .   2   2   .   2   2   .   2  \n
        040 062 062 056 062 062 056 062 062 056 062 012
0000034
0000000   3   3   .   3   3   .   3   3   .   3       N   O       E   S
        063 063 056 063 063 056 063 063 056 063 040 116 117 040 105 123
0000020       1   1   .   1   1   .   1   1   .   1  \n
        040 061 061 056 061 061 056 061 061 056 061 012
0000034
Realizar operación

EDIT2: With this patch works although I still do not understand why it fails in the other way.

... Z=${DATOS[i]}
    X=${LOG[r]} 
    if [ "$Z" == "$X" ]; then
    #if [ "$DATOS[i]" == "$LOG[r]" ] ; then
...

EDIT3: I have tried to clean it as you indicate in the answer but it does not work.

...
    #Z=${DATOS[i]}
    #X=${LOG[r]}    
    #if [ "$Z" == "$X" ]; then
    LOGCLEAN=${LOG[r]//[$'\t\r\n']}
    echo "LOGCLEAN: $LOGCLEAN"
    if [ "$DATOS[i]" == "$LOGCLEAN" ] ; then
...

The result is repeated:

Realizar operación
0000000   2   2   .   2   2   .   2   2   .   2       N   O       E   S
        062 062 056 062 062 056 062 062 056 062 040 116 117 040 105 123
0000020       1   1   .   1   1   .   1   1   .   1  \n
        040 061 061 056 061 061 056 061 061 056 061 012
0000034
Realizar operación
0000000   1   1   .   1   1   .   1   1   .   1       N   O       E   S
        061 061 056 061 061 056 061 061 056 061 040 116 117 040 105 123
0000020       1   1   .   1   1   .   1   1   .   1  \n
        040 061 061 056 061 061 056 061 061 056 061 012
0000034
0000000   1   1   .   1   1   .   1   1   .   1       N   O       E   S
        061 061 056 061 061 056 061 061 056 061 040 116 117 040 105 123
0000020       2   2   .   2   2   .   2   2   .   2  \n
        040 062 062 056 062 062 056 062 062 056 062 012
0000034
Realizar operación
0000000   3   3   .   3   3   .   3   3   .   3       N   O       E   S
        063 063 056 063 063 056 063 063 056 063 040 116 117 040 105 123
0000020       1   1   .   1   1   .   1   1   .   1  \n
        040 061 061 056 061 061 056 061 061 056 061 012
0000034
0000000   3   3   .   3   3   .   3   3   .   3       N   O       E   S
        063 063 056 063 063 056 063 063 056 063 040 116 117 040 105 123
0000020       2   2   .   2   2   .   2   2   .   2  \n
        040 062 062 056 062 062 056 062 062 056 062 012
0000034
0000000   3   3   .   3   3   .   3   3   .   3       N   O       E   S
        063 063 056 063 063 056 063 063 056 063 040 116 117 040 105 123
0000020       1   1   .   1   1   .   1   1   .   1  \n
        040 061 061 056 061 061 056 061 061 056 061 012
0000034
Realizar operación

FINAL EDIT: Here I leave the functional script:

A="1" #El primer dato es aceptado aunque no haya comparación con $LOG
DATOS=( 'cat archivo ' )
CONT5=${#DATOS[@]}
for i in "$DATOS"
do

    for (( i=0 ; i<$CONT5 ; i=i+1 )); do
        for (( r=0; r<$CONT5; r=r+1 )); do
            if [ -z "${LOG[r]}" ]; then
                echo "Vacío" > /dev/null
            else

                if [ "${DATOS[i]}" == "${LOG[r]}" ] ;   then
                    #echo "${DATOS[i]} ES IGUAL A ${LOG[r]} "
                    A="0"
                else
                    echo "" > /dev/null
                    #echo "${DATOS[i]} NO ES ${LOG[r]}"
                fi
                    fi
                        done
                        if [ $A -eq 1 ] ; then
                            echo "Realizar operación"
                        fi

                        LOG[$i]=${DATOS[i]}
                        A="1"
                    done
                done

The fact of blocking the operation in the case that a match is found is that when you operate with a file that has many items, and some are repeated, you must filter by coincidence to avoid a bad filtering. You can do the test in this latest fully functional script.

Thank you all for the answers

    
asked by vurgeando 23.05.2018 в 21:07
source

3 answers

3

If you want to not repeat an operation with a data processed previously this is what you need:


#!/bin/bash

#Declaracion de variables
declare -a DATOS
declare -a LOG
declare -i z
declare -i y

# Asignar valos a variables
DATOS=$( cat archivo )
LOG="null" # Valor incial para que entre al bucle la primera vez, se sobreescribe la primera vez
z=0 # Contador
y=0 # Comprobación de si un valor es igual a otro

# Bucle del array DATOS
for i in ${DATOS}; do
    # Logitud del array LOG, es variable, se redefine cada vez que entra en el bucle
    CONT5=${#LOG[@]}
    # Bucle del array LOG
    for (( r=0; r<$CONT5; r=r+1 )); do
        # Comprueba que el valor de del array de DATOS es igual al de LOG
        if [ "${i}" == "${LOG[$r]}" ]; then
                echo "${i} ES IGUAL A ${LOG[$r]}"
                # Si $r es igual a un valor anterior finaliza el bucle
                r=$CONT5
                y=1
            fi
    done
    # Se almacena el en array de LOG el valor de DATOS anteriormente comprobado
    if [ $y -ne 1 ]; then
        LOG[$z]=${i}
        echo "${i} NO ES ${LOG[$r]}"
        echo "Realizar operacion"
    fi
    y=0
    # Aumentar el contador que usamos para el array LOG
    z=$((z + 1))
done

The "for i in $ ARRAY" loop runs through the entire array, regardless of the number of items it contains, so the second loop of "for i = 0" is not necessary, plus it is crushing the $ i of the loop previous.

Inside the "for in" loop we use $ i, to identify the value of the array we checked.

The LOG arrays store all the previously checked data, if the operation has already been executed with that value, nothing is done, so the "Perform operation" must go in the "else" which is when it has not been executed .

    
answered by 24.05.2018 / 10:55
source
2

Edit

The topic is how the parameters in the comparison are expanded, example:

$ array[0]=01234567890abcdefgh
$ echo "|$array[0]|"
|01234567890abcdefgh[0]|
$ echo "|${array[0]}|"
|01234567890abcdefgh|

$ array[1]=${array[0]}
$ echo "|${array[1]}|"
|01234567890abcdefgh|


$ if [ "$array[0]" == "$array[1]" ]; then echo "SI"; else echo "NO"; fi
NO
$ if [ "${array[0]}" == "${array[1]}" ]; then echo "SI"; else echo "NO"; fi
SI

In your case you are comparing "$DATOS[i]" == "$LOG[r]" and should be "${DATOS[i]}" == "${LOG[r]}" .

I leave the original answer here

According to the dump it would seem that the extra \n is part of echo but in the doubts it would clean $LOG with Parameter Expansion . I include as in the reference tabs '\t' , newlines '\n' and carriagreturns '\r' .

LOGCLEAN=${LOG//[$'\t\r\n']}

example:

$ LOG=$'111.111.111.111\n'
$ echo "|$LOG|"
|111.111.111.111
|
$ LOGCLEAN=${LOG//[$'\t\r\n']}
$ echo "|$LOGCLEAN|"
|111.111.111.111|

$ echo "$LOG" | od -cb
0000000   1   1   1   .   1   1   1   .   1   1   1   .   1   1   1  \n
        061 061 061 056 061 061 061 056 061 061 061 056 061 061 061 012
0000020  \n
        012
0000021

$ echo "$LOGCLEAN" | od -cb
0000000   1   1   1   .   1   1   1   .   1   1   1   .   1   1   1  \n
        061 061 061 056 061 061 061 056 061 061 061 056 061 061 061 012
0000020

reference:

link

    
answered by 23.05.2018 в 23:36
1

Another possible solution would be to approach the problem in another way. Read the file first by passing it an uniq filter (so that only the non-repeated lines come out) and then proceed with your analysis. This would be:

#!/bin/bash
filelines='cat archivo.txt | uniq'
for line in $filelines ; do
    echo $line
done

with the previous thing you cross all the lines of the file.txt that are NOT repeated (due to the uniq) and inside the loop it prints each line.

In your case, the echo $ line would change it for the process you do

    
answered by 23.05.2018 в 23:54