Testando se existe uma String dentro de uma matriz de strings

2

Estou escrevendo um script que compara as três primeiras letras de cada linha (usando o corte para obtê-las) em um arquivo para seqüências de caracteres dentro de uma matriz. Eu já dei uma olhada, mas as soluções que encontrei não funcionaram no meu sistema.

Agora mesmo, parece assim:

weekdays=([Mon]=1 [Tue]=1 [Wed]=1 [Thu]=1 [Fri]=1 [Sat]=1 [Sun]=1)
input="/Foo/Bar.log"

while read -r line
do

cutline="$(echo ${line} | cut -c 1-3"

if [[ ${weekdays["$cutline"]} ]]
then
echo "Match"
else
echo "No Match"
fi

done < ${input}

A linha é cortada corretamente, mas algo durante o teste retorna um falso positivo, pois não importa quais sejam as 3 primeiras cartas, ele retorna um "Correspondência".

Quando eu verifiquei o script com -x ele me mostrou, em vez do teste real que ele usou

[[ -n 1 ]]

E quando testei com a [ ] expresion, mostrei um 1

Verifica cada caractere no array e não apenas as palavras inteiras, ou há algo mais errado com isso?

Se não houver problema, há outra maneira de comparar as três primeiras letras de uma linha com tudo que está em uma matriz antes de continuar com a próxima?

Como uma nota lateral: estou de fato executando o Bash 4, então matrizes associativas devem funcionar

    
por Benjo 23.09.2016 / 10:55

2 respostas

4

O erro básico é que você não está realmente declarando uma matriz associativa:

$ weekdays=(["Mon"]=1 ["Tue"]=1 ["Wed"]=1 ["Thu"]=1 ["Fri"]=1 ["Sat"]=1 ["Sun"]=1)
$ echo ${weekdays[@]}
1
$ echo ${weekdays[0]}
1
$ echo ${weekdays[2]}

$

Não sei ao certo como o bash está lidando com ele e por que ele leva apenas um 1 , mas tenho certeza de que esse não é um array associativo. Conforme explicado em man bash (ênfase minha):

An indexed array is created automatically if any variable is assigned to using the syntax name[subscript]=value. The subscript is treated as an arithmetic expression that must evaluate to a number. To explicitly declare an indexed array, use declare -a name (see SHELL BUILTIN COM‐ MANDS below). declare -a name[subscript] is also accepted; the sub‐ script is ignored.

Associative arrays are created using declare -A name.

Então, tente isso e funcione conforme o esperado:

declare -A weekdays=(["Mon"]=1 ["Tue"]=1 ["Wed"]=1 ["Thu"]=1 ["Fri"]=1 ["Sat"]=1 ["Sun"]=1)

Dito isso, seu script é um pouco mais complexo do que você precisa. Aqui está uma versão mais simples usando a mesma abordagem:

#!/bin/bash
declare -A weekdays=(["Mon"]=1 ["Tue"]=1 ["Wed"]=1 ["Thu"]=1 ["Fri"]=1 ["Sat"]=1 ["Sun"]=1)
input="/Foo/Bar.log"

cut -c 1-3 "$input" | while read -r line; do
    if [[ ${weekdays["$line"]} ]]
    then
            echo "Match : $cutline : ${weekdays[$line]}"
    else
            echo "No Match"
    fi
done    

Embora eu provavelmente faça assim:

#!/bin/bash
cut -c 1-3 "$1" | while read -r line; do
        case $line in
        "Mon"|"Tue"|"Wed"|"Thu"|"Fri"|"Sat"|"Sun")
                        echo yes;;
                *)
                        echo no;;
        esac
done

Em seguida, execute o script com o nome do arquivo de destino como um argumento:

script.sh /Foo/Bar.log"
    
por 23.09.2016 / 11:11
3

Eu usaria uma chamada de uma ferramenta de processamento de texto para processar texto , não várias ferramentas para cada linha de entrada:

awk -v 'weekday=(Mon|Tue|Wed|Thu|Fri|Sat|Sun)' '
  {print ($0 ~ "^" weekday ? "" : "No ") "Match"}' < "$input"

Você usaria um loop se precisasse executar um aplicativo específico para cada linha da entrada, mas se for apenas processamento de texto, como a saída da linha para algum arquivo, então awk pode fazer como:

awk -v 'weekday=Mon|Tue|Wed|Thu|Fri|Sat|Sun' '
  (day = substr($0, 1, 3)) ~ weekday {
    print substr($0, 4) > day ".txt"
  } < "$input"
    
por 23.09.2016 / 11:40