7.3 データの抽出と編集
Linux Essentials Online Text | 2021/07/26

情報の抽出(grep)

grepは、特定の文字列が含まれるファイルを検索するコマンドです。前項で説明した「|」と組み合わせる事で、標準入力されるデータに対し検索を行うことも可能です。

書式:

grep [オプション] 検索条件 指定ファイルまたはパス

主なオプション:

-cパターンにマッチした行の行数のみ表示。
-eor 検索を行う。
-f検索パターンをファイルから読み込む。
-i大文字、小文字を区別しない。
-n検索結果を表示する際に、行番号を表示する。
-vパターンにマッチしない行を表示する。

指定ファイルには、「*」のようなワイルドカード(不特定の文字列を表現するのに利用される記号)を利用した複数ファイルの指定する事も可能です。検索条件には正規表現が用いられます。

正規表現

正規表現は、grepのみならずLinuxで用いられるパターンマッチや、他のプログラミング言語でも利用されている非常に重要な機能です。正規表現は通常の文字とメタキャラクタと呼ばれる特別な意味を持った記号を組み合わせて表記する検索条件パターンのことです。
1つの形式で、膨大な文章の中から複数の文字列を探し出すことができます。

例えば「^」という文字は「行頭」、「.」は「任意の1文字」、「+」という文字は「直前の要素の1回以上の繰り返し」を意味します。主に用いられる記号は次の通りです。

正規表現意味
^
キャレット(カレット)
行頭を表します。
$
ダラー(ドルマーク)
行末を表します。
.
ドット(ピリオド)
任意の一字を意味します。
*
アスタリスク
直前の文字の0回以上の繰り返しを意味します。
+
プラス
直前の文字の1回以上の繰り返しを意味します。

クエスチョン
直前の文字の0または1回の繰り返しを意味します。
[...]
大括弧(ブラケット)
括弧の中の任意の一字を意味します。
「-(ハイフン)」で範囲ができます。例:[a-z][A-Z][0-9]
「^(カレット)」が文字列の先頭にある場合はそれらの文字が含まない事を意味します。
|
パイプ
or と同じ意味。
\
バックスラッシュ
正規表現の記号をエスケープします。
円マークでも同じ意味。
!
エクスクラメーション
直後の条件を否定します。

利用例

^a			:aで始まっている行すべて
b$			:bで終わっている行すべて
a.b			:aとbの間に1文字入っている
[ab]ab		:aもしくはbで始まるab(aab, bab)
[^ab]ab		:aもしくはbで始まらない(not)で、abが続くもの(例:xab, zab等)

<実習: grepによる文字列の検索>

起動ログから、ネットワークインターフェースが認識しているか確認します。

$ grep Network /var/log/dmesg
[    2.100032] e1000: Intel(R) PRO/1000 Network Driver - version 7.3.21-k8-NAPI
[    2.868369] e1000 0000:00:03.0 eth0: Intel(R) PRO/1000 Network Connection

/var/log/dmesg ファイルは、カーネルのイベントを出力したログです。カーネルは電源を入れた直後から動き始めるため、起動したときの全てのイベントが記録されます。上記では、Intel製の「PRO/1000」というインターフェースが見つかり、「e1000」というデバイスドライバが読み込まれ、正常に認識たことを示すログです。

なお、以下でも同じ結果が表示されます。

$ cat /var/log/dmesg | grep Network

ただし、先の例とは若干意味合いが違います。

grepコマンドでは、/var/log/dmesgファイルの中から直接「Network」という単語が含まれる行を探し出して抽出していますが、catコマンドとパイプを使った例では、最初にcatコマンドを使ってファイル全体を表示してから、grepコマンドに渡されて 「Network」という単語が含まれる行を探します。
参照しているファイルが同じなので結果は同じですが、後者は処理が1つ多いため、厳密にはシステムリソースを多く消費することになります。微々たる差ですが、回数が増えれば無視できない差につながります。自動処理させる場合などは注意が必要です。

<実習: 正規表現を使ったgrep検索>

$ ls /usr/bin | grep -E ^c.t$
cat
cut
cvt
$ ls /usr/bin | grep -E ^c[au]t$
cat
cut
[-E]オプションを使ったgrepコマンドを使用すると、検索条件に正規表現を使うことができます。
1つ目の例では、「ls /usr/bin」で表示される結果の中から、「c」から始まり「t」で終わる3文字(2文字目は任意の1文字)に該当する結果が抽出されています。
2つ目の例では、「ls /usr/bin」で表示される結果の中から、「c」から始まり「t」で終わる3文字で且つ、2文字目は「a」または「u」に該当する結果が抽出されています。

次に、以下を実行してみてください。

$ ls /usr/bin | grep -E ss+
$ ls /usr/bin | grep -E ss*
$ ls /usr/bin | grep -E ss?

上記コマンドを実行すると、表示される行数が多いためここには記載しませんが、文末に「+」をつけた時と「*」「?」で出力結果が違うことに気が付くでしょうか。「+」は直前の文字を1回以上繰り返すため、「ss」または「sss」が含まれる行が抽出されますが、「*」「?」では直前の文字を0回以上繰り返すことになるため、これに加えて「s」が含まれる行が抽出されます。

情報の並び替え(sort)

sortコマンドは、表示された内容を昇順または降順に並び替えることができるコマンドです。

式:

sort [オプション] ファイル名

主なオプション:

-r逆順で並び替える
-k NN列目のデータを並び替える
-n数値として並び替える
-t 文字フィールドの区切り文字を指定する(デフォルトはスペース)

実習: sortの実行

sortコマンドを実施するためにsort-testファイルを作成します。
下記のコマンドを入力してください。
※環境に応じて引数を変更する必要はありません。記載された通り、入力してください。

$ ls -la | grep $USER | awk '{print $2,$3,$4,$5}' > sort-test
$ cat sort-test
4 lpic-user lpic-user 231
4 lpic-user lpic-user 4096
(以下省略)

sort-testの中身は、下記のように、4つのブロックに分かれ、両端が数字、真ん中はアカウント名になっていればOKです。

それでは、このファイルの内容を並び替えてみます。

$ sort sort-test
1 lpic-user lpic-user 0
1 lpic-user lpic-user 0
(以下省略)

並び替わったのがわかるでしょうか。一番左にある文字を使って昇順(数字なら0から9、アルファベットならaからz、またはAからZ)で並び替えが行われます。

実習: -rオプションを使っての逆順並び替え

今度は、降順に並べてみましょう。

$ sort -r sort-test
8 lpic-user lpic-user 172
4 lpic-user lpic-user 4096
(以下省略)

「-r」オプションを使って実行すると、降順(数字なら9から0、アルファベットならzからa、またはZからA)で並び替えが行われます。

実習: 4列目のデータ並び替え

さて、今までは行の一番左の文字、つまり1文字目で並び替えを行いました。sortコマンドでは、他の列をつかって並び替えを行うことができます。sortする列を変更したい場合は 「-k」オプションを使用します。

$ sort -k 4 sort-test
1 lpic-user lpic-user 0
1 lpic-user lpic-user 0
1 lpic-user lpic-user 12183
1 lpic-user lpic-user 14264
8 lpic-user lpic-user 172
(以下省略)

「-k」オプションの後ろに指定した数字に該当する「列」を使ってsort、つまり一番右にある数字を使って並び替えが行われています。

さて、ここで並び方がおかしい事に気がついたでしょうか。

0 → 0 → 12183 → 14264 までは問題ありませんが、その後172と並んでいます。実はこれ、間違っているわけではないのです。実は、sortコマンドは対象を文字として判断しています。
このような動作を辞書式ソートと呼びます。アルファベットの単語を並び替えるのと同様に、数字も最初の1文字を見て、0 → 1 と並び替えたのち、1文字目が「1」のものは2文字目を見て2 → 4 → 7と並び替え、それでも順位が決まらない場合は3文字目、4文字目を見ていきます。

今回使用している数字は「ファイルサイズ」です。数字の羅列ではなく「数値」として扱われなければならず、辞書式ソートのような文字列ではなく、数値として並び替えることが必要です。数値を並び替える動作を数値式ソートと呼び、[-n]オプションを用いてソートします。

実習: 数値式ソートの実行

$ sort -k 4 -n sort-test
1 lpic-user lpic-user 0
1 lpic-user lpic-user 0
1 lpic-user lpic-user 18
8 lpic-user lpic-user 172
1 lpic-user lpic-user 178
(以下省略)

今度は、4列目の数字を「数値」としてsortすることができました。
ちなみに、「-r」オプションを追加すると、降順にすることも可能です。

各行から一部分を切り出す(cut)

ファイルの各行から指定した一部分を切り出し標準出力に表示するコマンドです。

書式:

cut [オプション] ファイル名

主なオプション:

-b NNバイト目を切り出す。
-c NN文字目を切り出す。
-f NNフィールド目を切り出す。
-d 文字フィールドの区切り文字を指定する(デフォルトはタブ)。

簡単に言うと、cutはテキストファイルを横方向に分割するコマンドです。csvデータなどの一覧表から、必要な項目だけを抜き出す時等に使います。

言葉ではわかりづらいと思います。下記、実習を用意していますのでコマンドを実行しながら理解してみてください。

実習: cutコマンドの実行

sortコマンド自習時に作成した「sort-test」ファイルを使用します。

cut -b 3-6 sort-test
lpic
lpic
(以下省略)

上記は、各行の3バイト目から6バイト目までを抜き出しています。小文字英語、大文字英語や数字、記号は半角文字と言い、1バイトでできています。つまり、3文字目から6文字目までを抜き出していることと同意です。

「-b」オプションはバイト単位で抜き出しますが、「-c」オプションは文字数単位で抜き出します。

cut -c 3-6 sort-test
lpic
lpic
(以下省略)

上記は、各行の3文字目から6文字目までを抜き出しています。対象が半角文字である場合、「-b」と「-c」は同じ動作になります。

1行中の、離れた場所を抜き出すことも可能です。
下記は、3バイト目から6バイト目、13バイト目から16バイト目を抜き出します。

cut -b 3-6,13-16 sort-test
lpiclpic
lpiclpic 
(以下省略)

下記のように、3バイト目以降すべてを抜き出す、ということもできます。

$ cut -b 3- sort-test
lpic-user lpic-user 231
lpic-user lpic-user 4096
(以下省略)

「-d」オプションを用いると区切り文字を指定することができます。この時、行の初めから最初の区切り文字までを1フィールド目、最初の区切り文字から次の区切り文字までを2フィールド目と、フィールドを作ることができます。

そして、フィールドを単位として抜き出すことができます。

$ cut -d " " -f 3 sort-test
lpic-user
lpic-user
(以下省略)

上記は、半角スペースを区切り文字としたときに、左から3つ目のフィールドを抜き出しています。
sortコマンドの「-k」オプションと同じような挙動ですが、異なるオプションを指定する点に注意してください。

行数・単語数・バイト数を表示する(wc)

wcコマンドは行数・単語数・バイト数等を表示します。

書式:

wc [オプション] ファイル名

主なオプション:

-cバイト数のみを表示する
-l行数のみを表示する
-m文字数のみを表示する
-w単語数のみを表示する

ファイルは[スペース]で区切り、複数指定することができます。複数指定した場合は合計値が表示されます。

実習: wcコマンドの実行

$ wc /var/log/dmesg
  498  4126 31282 /var/log/dmesg

オプションを指定しない場合は、行数・単語数・バイト数の順で表示されます。

オプションを指定すると、目的の数値のみ求めることができます。

$ wc -l /var/log/dmesg
501 /var/log/dmesg
$ cat /var/log/dmesg | grep CPU | wc -l
10

上記のようにパイプを使って標準入力されたデータの行数を調べることも可能です。
後者は、/var/log/dmesgの中でCPUが含まれる行数をカウントしたものです。

PAGE TOP