次のデータを含むファイルがあります(サンプルデータのみが表示されます。ファイルには最大2001行が含まれています)。
0001:3002:2018/07/16:12.34.31:ERR
0002:3002:2018/07/16:12.34.44:ERR
0003:3002:2018/07/16:12.34.57:ERR
0004:3002:2018/07/16:12.35.10:ERR
0005:3002:2018/07/16:12.35.23:ERR
0006:3002:2018/07/16:12.35.36:ERR
0007:3002:2018/07/16:12.35.49:ERR
0008:3002:2018/07/16:12.36.02:ERR
0009:3002:2018/07/16:12.36.15:ERR
たとえば、2018/07/16:12.36.15のようにbashスクリプトに日付を渡しましょう.このファイルの各行を読み、その行の日付を渡された日付と比較し、渡された日付より大きい日付を持つ行を返したいと思います。
今まで何をしたのか?
#!/bin/sh
SEARCH_DATE=$1
errorCodeFilePath=/home/.errorfile.log
lines=`cat $errorCodeFilePath`
for line in $lines; do
errorCodeDate=$(echo $line |grep -Eo '[[:digit:]]{4}/[[:digit:]]{2}/[[:digit:]]{2}:[[:digit:]]{2}.[[:digit:]]{2}.[[:digit:]]{2}');
if [ $errorCodeDate -ge $SEARCH_DATE ];
then
echo $errorCodeDate
fi
done
質問
日付比較が機能しているかどうかはわかりません。 「整数式エラーが予想されます」というメッセージが表示されます。私は本当に Bash スクリプトを書く方法を知らず、これが私の最初の試みです。
この日付比較を有効にするにはどうすればよいですか?また、日付比較が機能した後は、一致するすべての行の最初と2番目の間の数字を取得する必要があります。
ベストアンサー1
スクリプトはファイル全体を変数として読み込み、その変数の値を繰り返します。これには3つの問題があります。
- 最も一般的なケースでは、入力ファイルのサイズがわかりません。これは、場合によっては、変数が次のように大きくなる可能性があることを意味します。非常に大きい。
- ループ変数の引用符で囲まれていない値は、シェルを使用して空白(スペース、タブ、および改行)にデータを分割します。データに改行以外のスペースが含まれている場合、ループは誤った操作を実行する可能性があります。
- シェルは、ループの前に引用されていない変数の値に対してファイル名のグロービングを実行します。つまり、データに
*
または同じワイルドカードパターンが含まれている場合、[...]
これらのパターンは既存のファイル名と一致します。
この回答は、使用されたタイムスタンプがその後のタイムスタンプが以前のタイムスタンプ(少なくともPOSIXロケールでは)の後にソートされるという点で合理的であるという事実を利用します。
#!/bin/bash
while IFS= read -r line; do
timestamp=${line%:*} # Remove ":ERR" at the end
timestamp=${timestamp#*:*:} # Remove numbers from start ("0001:3002:")
if [[ "$timestamp" > "$1" ]]; then
# According to the current locale, the timestamp in "$timestamp"
# sorts after the timestamp in "$1".
printf "Greater: %s\n" "$line"
fi
done <file
スクリプトは、ファイルと同じ形式のタイムスタンプを唯一の引数として使用します。ファイルの内容を繰り返しfile
、各行のタイムスタンプを解析し、それをコマンドラインのタイムスタンプと比較します。>
演算子 in を使用した比較は、ファイルbash
のタイムスタンプが現在のロケールで指定されたタイムスタンプの後に辞書式でソートされた場合に true になります。比較が真の場合は、ファイルの行を印刷します。
行の終わりと始まりを削除して行のタイムスタンプを解析するための2つの別々の代替方法は、次のように置き換えることができます。
timestamp=$( cut -d ':' -f 3,4 <<<"$line" )
ただし、外部ユーティリティを呼び出すため、実行が遅くなります。
テスト:
$ bash script.sh '2018/07/16:12.36.00'
Greater: 0008:3002:2018/07/16:12.36.02:ERR
Greater: 0009:3002:2018/07/16:12.36.15:ERR
生の行ではなくファイルのタイムスタンプのみを出力するには、コマンドでに変更します"$line"
。"$timestamp"
printf
この場合、次のループを実行して作業を高速化することもできます。
#!/bin/bash
cut -d ':' -f 3,4 file |
while IFS= read -r timestamp; do
if [[ "$timestamp" > "$1" ]]; then
# According to the current locale, the timestamp in "$timestamp"
# sorts after the timestamp in "$1".
printf "Greater: %s\n" "$timestamp"
fi
done
cut
ここでは、ファイルから3番目と4番目の分離列(タイムスタンプ)を取得するために使用します:
。つまり、元の行を解析する必要はありません。
関連: