
ファイル内の各行の最初の 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
が、それが連想配列ではないことは確かです。説明されているようにman bash
(強調は筆者による):
構文 name[subscript]=value を使用して変数が割り当てられると、インデックス付き配列が自動的に作成されます。subscript は数値に評価される算術式として扱われます。インデックス付き配列を明示的に宣言するには、declare -a name を使用します (以下の SHELL BUILTIN COMMANDS を参照)。declare -a name[subscript] も受け入れられますが、subscript は無視されます。
連想配列は、declare -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
テキスト処理ツールを1回呼び出してテキストを処理します入力行ごとに複数のツールを使用するのではなく、
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"