助け合いフォーラム

LPIC

LPIC Lv1-101(Ver5.0)
問題ID : 3706
問題を開く
journalctlコマンドの出力結果を保存した「system.log」ファイルがあり、全ての行に「hh:mm:ss」形式で時刻が記録されている。17時台の行を抽出できるコマンドは次のうちどれか。(2つ選択)

正解

grep -E '17:[0-9]+:[0-9]+' system.log

grep -E '17:[0-5][0-9]:[0-5][0-9]' system.log

解説

ファイルや標準入力から、正規表現のパターンにマッチする文字列を含む行を抽出するにはgrepコマンドを利用します。

grepコマンドの書式は以下のとおりです。拡張正規表現を使用する場合は「-E」オプションを使用します。

grep [オプション] 検索パターン [ファイル名]

以下は主な正規表現とその使用例をまとめたものです。


17時台のログは「17:00:00」から「17:59:59」の範囲の時刻です。
選択肢を1つずつ確認します。

・grep -E '17:[0-9]+:[0-9]+' system.log
[0-9]は0~9のいずれかの数字、「+」は直前の文字の1回以上の繰り返しを表します。この場合に「+」で繰り返されるのは[0-9]のため、「hh:mm:ss」形式のファイルでは'17:[0-9][0-9]:[0-9][0-9]'による抽出と同様です。
この選択肢は「17:00:00」から「17:99:99」の範囲を抽出できます。結果として17時台のログは抽出されるので、正しいコマンドです。

・grep -E '17:[0-9]?:[0-9]?' system.log
「?」は直前の文字の0回もしくは1回の繰り返しなので、「17::」や「17:9:9」のような行が抽出の対象です。17時台のログは抽出されませんので、誤りです。

・grep -E '17:[0-59]:[0-59]' system.log
[0-59]は0~5,9のいずれかの数字を表すので、「17:0:0」や「17:2:4」のような行が抽出の対象です。17時台のログは抽出されませんので、誤りです。

・grep -E '17:00|59' system.log
「17:00|59」は「17:00」か「59」のいずれかの文字列が抽出の対象です。17時台のログは抽出されませんので、誤りです。

・grep -E '17:[0-5][0-9]:[0-5][0-9]' system.log
[0-5]は0~5のいずれかの数字、[0-9]は0~9のいずれかの数字を表すので、「17:00:00」から「17:59:59」の範囲を抽出できます。17時台のログは抽出されるので、正しいコマンドです。

したがって正解は
・grep -E '17:[0-9]+:[0-9]+' system.log
・grep -E '17:[0-5][0-9]:[0-5][0-9]' system.log
です。

以下は実行例です。赤い部分がgrepコマンドにマッチした文字列です。

参考

【正規表現】
正規表現とは、文字列の特定のパターンを認識する為に使用する表現方法です。文字列の検索や置換などを行う際に利用します。正規表現には基本正規表現(BRE: Basic Regular Expression)と拡張正規表現(ERE: Extended Regular Expression)があります。

以下は主な正規表現とその使用例をまとめたものです。


正規表現には次のような基本の概念があります。
・特殊文字
「|」や「\(エスケープ文字)」などのように特殊な意味を持つ文字のことです。

・文字クラス
「[ ]」内の文字集合のことです。

・数量詞
「*」や「+」などのように直前の文字の繰り返し回数を示す文字のことです。

・アンカー
「^」や「$」などのように文字列内での位置を示す文字のことです。

なお、正規表現の「*」と、シェルによって解釈されるメタキャラクタの「*」では意味が異なるので注意してください。シェルは「*」を0文字以上の文字列と解釈します。
正規表現は明示的に「'」(シングルクォーテーション)や「"」(ダブルクォーテーション)の引用符で囲う事ができます。これらの引用符で囲まれた正規表現の記号は、シェルにメタキャラクタとして扱われなくなります。

正規表現を利用する主なコマンドには「sed」「grep」があります。

■sed
ファイルや標準入力の内容を編集して表示するコマンド

例)「test.txt」ファイルの「#」から始まる行を削除して出力する場合
 $ sed '/^#/d' test.txt

■grep
ファイルや標準入力から、検索パターンにマッチする文字列を含む行を抽出するコマンド

例)1から5までのいずれかの文字がある行を「test.txt」ファイルから抽出する場合
 $ grep '[1-5]' test.txt

[基本正規表現と拡張正規表現]
基本正規表現と拡張正規表現の違いに注意してください。

grepコマンドは、-Eオプションを付けない場合は検索パターンを基本正規表現と判断します。
grepコマンドの検索パターンで拡張正規表現を使うには、-Eオプションを指定します(egrepコマンドと同様)。
例)拡張正規表現「+」を使った抽出


なお、拡張正規表現の「?」「+」は、基本正規表現では「\?」「\+」で同様の指定ができます。
例)基本正規表現で「+」を扱う場合
上に戻る

grepとgrep -Eまたはegrepの使い分けについて

投稿日 2023/07/24

この問題の正答は、以下とされています。
①grep -E '17:[0-5][0-9]:[0-5][0-9]' system.log
②grep -E '17:[0-9]+:[0-9]+' system.log

①は、拡張正規表現が使用されていないので、-Eがなくてもよい
のに対して、②は、拡張正規表現が使用されているため
-Eをつけるかegrepを使用しなければならない認識です。

ということは、常に -E付き または egrepを使えば
拡張正規表現が含まれる場合も、含まれない場合も対応できる
ので、 -E/egrepのみを使用するほうが拡張正規表現で
失敗するリスクがないのでよいと考えられる様に感じました。

上記は必ずしもそうではなく、-E/egrepではなく
grepを使用しなければならないケースが存在するのでしょうか。

あるいは、機能的には上記でよいが、-E/egrepの方が
処理速度が遅い、多くのリソースを必要とするなど
なんらかのデメリットがあるのでしょうか。

ご存じの方がおられましたら、教えて下さい。
宜しくお願いします。

2023/07/26 20:30

ここはぶっちゃけていうと「好きに使ったらいい」って話になるかなと思います。
判断基準というのも変ですが、例えば

  • 通常のgrep(BER)では表現が難しい検索文字列を使う必要がある場合なら egrep / grep -E を使うべき
  • 特に考えず、ただ文字列をヒットさせたいだけなら grep で十分
  • あとは好みや「入力文字数」(grepなら4文字ですが、egrepは5文字、grep -Eだと7文字)

なんかでいいんじゃないかなと思います。

ちなみに速度についてはあまり気にしたことないですが、単純な文字の検索程度なら確かにgrepの方が速いのかもしれませんね。Linuxカーネル6.4.6のソース全体に対してkprintという文字列を検索しただけですが、何回か実行してもgrepに比べてegrep / grep -Eの方が数秒遅かったです。

# time grep -r "kprint" * | wc -l
1

real    1m11.317s
user    0m2.010s
sys     0m4.708s

# time egrep -r "kprint" * | wc -l
1

real    1m18.934s
user    0m1.952s
sys     0m4.645s

# time grep -E -r "kprint" * | wc -l
1

real    1m14.637s
user    0m1.943s
sys     0m4.474s


コメント

k kz5835

2023/07/27 00:15

arashi1977様 ご回答、有難うございます。大変参考になりました。

この返信に対して
コメントを記入できます

この投稿に対して返信しませんか?