文字列配列に文字列があるかどうかをテストする

文字列配列に文字列があるかどうかをテストする

私はファイルの各行の最初の3文字を(cutを使用して取得した)配列の文字列と比較するスクリプトを書いています。私は周りを見回しましたが、見つけた解決策は私のシステムでは機能しません。

これで、次のようになります。

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}

行は正しく切り捨てられましたが、最初の3文字が何でも「一致」を返すため、テスト中に何かが偽の肯定を返します。

-x を使用してスクリプトを検査すると、実際のテストの代わりに使用されるとマークされます。

[[ -n 1 ]]

表現でテスト[ ]すると1

完全な単語の代わりに配列のすべての文字をチェックしますか、それとも別の問題がありますか?

もしそうなら、次の文字に移動する前に行の最初の3文字と配列のすべての文字を比較する他の方法はありますか?

注:私は実際にBash 4を実行しているので、連想配列が機能するはずです。

答え1

基本的なエラーは、実際には連想配列を宣言しないことです。

$ 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]}

$

bashがこれをどのように処理するのか、なぜ1つだけ取るのか完全にはわかりませんが、1連想配列ではないと確信しています。man bash(強調)の説明に従って:

name[subscript]=value 構文を使用して変数を割り当てると、インデックス配列が自動的に生成されます。下付き文字は、数値として評価する必要がある算術式として扱われます。インデックス付き配列を明示的に宣言するには、discover -a nameを使用します(以下のSHELL BUILTINコマンドを参照)。 -a name[subscript] ステートメントも許可されます。

連想配列は、-A name ステートメントを使用して生成されます。

したがって、これを試してください。期待どおりに機能します。

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

つまり、スクリプトは必要以上に少し複雑です。同じ方法を使用するより簡単なバージョンは次のとおりです。

#!/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    

私はこれを行うことができますが:

#!/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

次に、ターゲットファイル名を引数として使用してスクリプトを実行します。

script.sh /Foo/Bar.log"

答え2

テキスト処理ツールを呼び出してテキストを処理します。、すべての入力行に複数のツールがあるわけではありません。

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

各入力行に対して特定のアプリケーションを実行する必要がある場合はループを使用できますが、単にテキスト処理(たとえば、一部のファイルに行を出力するなど)の場合は、次のことができますawk

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

関連情報