はじめに

こんにちは。キャスレーコンサルティング インフラエンジニアのでKIです。

今回は、インフラエンジニアに成りたての皆様が「ちょっと楽になるかもしれない?」方法をお送りします。
エンジニアとしての活動を行っているとき、例えばこんなことを思ったことはありませんか?
・サーバ内の大量ログから、必要な情報だけ抽出したい。
・コマンドの実行結果を繰り返し確認したい。
・複数のコマンドを同時に実行したい。

そこで今回は、これらをたったワンライン(1行)で実行し効率化を図る方法について紹介します。
なお、本記事はサーバでの使用を想定し、基本的なコマンドのみ記載いたします。
※例えば「tailf」や「egrep」などの類似コマンドがあります。

  • tail, grepによる、リアルタイムログの表示、文字列抽出
  • sort, uniqによる、重複削除
  • コマンドの繰り返し実行

リアルタイムログ表示

サーバなどのログをリアルタイムに監視する場合は、「tail -f」を使います。

# tail -f xxx.log (13:00に実行)
11:11 err
11:00 Warning
11:00 Error
12:00 err
12:00 err
12:00 Error
12:00 OK
12:00 Error
12:00 warn
13:02 Error (13:02に書き込まれたものが新たに表示)

ファイルの末尾を表示する tail コマンドに -f オプションをつけることで、対象ファイルに追記されたログがリアルタイムで随時表示されていきます。

文字列抽出

リアルタイムログに出力されているエラーやワーニングを抽出する場合は、「grep」を併せて使います。

# tail -f xxx.log | grep -i -e err -e warn
11:11 err
11:00 Warning
11:00 Error
12:00 err
12:00 err
12:00 Error
12:00 Error
12:00 warn
13:02 Error

grep は文字列の中から正規表現を使って抽出を行うコマンドです。
コマンドオプション[-i]で大文字、小文字区別せず、[-e]でor検索となります。

ちなみに tail と grep の間にある “|” は「パイプ」または「パイプライン」と呼ばれ、「コマンドの出力結果を他のコマンドへ引き継ぐ」際によく使います。
この例だと「tail でファイルの中身を表示しなさい」→「その中から err または warn という文字列を探してください」といった意味になります。

行数のカウント

エラー件数を確認する場合は、「wc -l」を使い行数をカウントします。

# cat xxx.log | grep -i err | wc -l
5

wc は行数や単語数を数えるコマンドです。
-l オプションをつけることにより「行数」をカウントできるようになります。
全体のコマンドの意味は
「xxx.log の中身を見なさい」→「err という文字列を探しなさい」→「それは何行みつかりましたか?」
となり、今回は5件のエラーが見つかったことになります。

重複の削除

重複行を削除する場合は、「uniq」を使います。

# cat xxx.log | sort | uniq
11:00 Error
11:00 Warning
11:01 err
11:02 err
11:10 err
11:11 err
12:00 Error
12:00 OK
12:00 err
12:00 warn
13:02 Error

uniq は重複を取り除くコマンドです。
cat でファイルを見て、sort で並べ替えたものから、重複を取り除く指令を実行しています。

範囲の抽出

指定範囲の時刻で抽出する場合は、「grep」を使い1列目の時間を指定します。

# cat xxx.log | sort | uniq | grep 11:0[0-2]
11:00 Error
11:00 Warning
11:01 err
11:02 err

先ほどは grep で “err” や “warn” といった文字列を抽出しましたが、本来 grep は正規表現で抽出ができるコマンドです。
このコマンドでは、正規表現で 11:0[0 から 2 までのいずれか] と指定しているため、11:00 / 11:01 / 11:02 を含むログが表示されます。

項目の抽出

警告の種類を確認する場合は、「awk」を使い2列目を抽出し整形したものを表示します。

# cat xxx.log | awk '{print $2}' | sort | uniq
Error
OK
Warning
err
warn

awk コマンドは、テキストの加工やパターン処理を行うコマンドです。
今回は {print $2} を指定していますが、これは「2番目の塊を標準出力に出力する」ことを意味しています。
このケースで {print $1} を指定すると “11:00” “11:01” “11:02” “11:10” などの文字列を抽出することができます。

#cat xxx.log | awk '{print $1}' | sort | uniq
11:00
11:01
11:02
11:10
11:11
12:00
13:02

サブフォルダを含むファイルの検索

ファイル内の文字列の検索はgrepで行いますが、ファイルやディレクトリ名を検索する場合は、「find」コマンドを使用します。

#find . -type f -name "*.txt" | xargs ls -l
-rw-r--r-- 1 k-itou k-itou 7 Oct  6 21:36 ./test/euc_test_01.txt
-rw-r--r-- 1 k-itou k-itou 7 Oct  6 21:36 ./test/euc_test_02.txt
-rw-r--r-- 1 k-itou k-itou 7 Oct  6 21:36 ./test/euc_test_03.txt
-rw-r--r-- 1 k-itou k-itou 7 Oct  6 21:36 ./test/euc_test_04.txt
-rw-r--r-- 1 k-itou k-itou 7 Oct  6 21:36 ./test/euc_test_05.txt
-rw-r--r-- 1 k-itou k-itou 7 Oct  6 21:36 ./test/euc_test_06.txt
-rw-r--r-- 1 k-itou k-itou 7 Oct  6 21:36 ./test/euc_test_07.txt
-rw-r--r-- 1 k-itou k-itou 7 Oct  6 21:36 ./test/euc_test_08.txt
-rw-r--r-- 1 k-itou k-itou 7 Oct  6 21:36 ./test/euc_test_09.txt
-rw-r--r-- 1 k-itou k-itou 7 Oct  6 21:36 ./test/euc_test_10.txt
-rw-r--r-- 1 k-itou k-itou 0 Oct  6 15:47 ./xxx.dir/test_01.txt
-rw-r--r-- 1 k-itou k-itou 0 Oct  6 15:47 ./xxx.dir/test_02.txt
-rw-r--r-- 1 k-itou k-itou 0 Oct  6 15:47 ./xxx.dir/test_03.txt
-rw-r--r-- 1 k-itou k-itou 0 Oct  6 15:47 ./xxx.dir/test_04.txt
-rw-r--r-- 1 k-itou k-itou 0 Oct  6 15:47 ./xxx.dir/test_05.txt
-rw-r--r-- 1 k-itou k-itou 0 Oct  6 15:47 ./xxx.dir/test_06.txt
-rw-r--r-- 1 k-itou k-itou 0 Oct  6 15:47 ./xxx.dir/test_07.txt
-rw-r--r-- 1 k-itou k-itou 0 Oct  6 15:47 ./xxx.dir/test_08.txt
-rw-r--r-- 1 k-itou k-itou 0 Oct  6 15:47 ./xxx.dir/test_09.txt
-rw-r--r-- 1 k-itou k-itou 0 Oct  6 15:47 ./xxx.dir/test_10.txt

「find」コマンドの「.」はカレントディレクトリ、「-type f」はファイル、
「-name “*.txt”」はファイル名の末尾に.txtのものを示しています。
「xargs」はfindの実行結果が1行ごとに出力されるため、「ls -l」の引数に
使用することができませんので、「xargs」で空白で区切られた文字列へ変換しています。

#find . -type f -name "*.txt"
./xxx.dir/test_05.txt
./xxx.dir/test_03.txt
./xxx.dir/test_10.txt
./xxx.dir/test_02.txt
./xxx.dir/test_04.txt
./xxx.dir/test_06.txt
./xxx.dir/test_09.txt
./xxx.dir/test_01.txt
./xxx.dir/test_08.txt
./xxx.dir/test_07.txt
#find . -type f -name "*.txt" | xargs echo
./xxx.dir/test_05.txt ./xxx.dir/test_03.txt ./xxx.dir/test_10.txt ./xxx.dir/test_02.txt ./xxx.dir/test_04.txt ./xxx.dir/test_06.txt ./xxx.dir/test_09.txt ./xxx.dir/test_01.txt ./xxx.dir/test_08.txt ./xxx.dir/test_07.txt 

※「find」コマンドはファイル編集コマンドと併せると一括処理に便利なのですが、コマンドを間違えると思わぬファイル削除やファイルの中身が消えたりしてしまうのでご注意ください。また、ファイル数が多い場合はサーバへの負荷もかかります。

繰り返しコマンドを実行

通信状況確認や大容量ファイル転送状況を繰り返し確認する場合は、
コマンドを繰り返し実行する「while」を使います。
なお、コマンドの繰り返し実行は、処理内容によってはサーバに負荷が掛かる場合があります。そのため本番環境で実行する場合は、検証環境でしっかりと動作確認した後に実施することを強くお勧めします。

# while sleep 1; do ls -l; done
-rw-r--r-- 1 root root 146 9月 10 08:41 xxx.log
合計 4
-rw-r--r-- 1 root root 146 9月 10 08:41 xxx.log
合計 4
-rw-r--r-- 1 root root 146 9月 10 08:41 xxx.log

while を使って sleep 1 を指定することで、1秒間隔で「ls -l」を実行し(do でコマンド指定)、結果を表示します。
このようにすることで、1秒後ごとにファイルサイズを確認できます。
終了したい場合は、ショートカットキー[Ctrl + c] で停止します。

[;] の改行を使わない場合は、下記のようにエンターを押して1行ずつコマンドを書くこともできます。

# while sleep 1
do
ls -l
done
-rw-r--r-- 1 root root 146 9月 10 08:41 xxx.log
合計 4
-rw-r--r-- 1 root root 146 9月 10 08:41 xxx.log
合計 4
-rw-r--r-- 1 root root 146 9月 10 08:41 xxx.log
# while sleep 1; do ls -l; done

ショートカットキー[Ctrl + c]で停止した後、上矢印キーを押してコマンドヒストリを確認すると一行で書いたもので表示されます。

複数コマンドの実行

1秒間隔で 「ls -l」の実行結果が連続して表示されて見ずらいため、クリアコマンド「clear」で画面を一旦消去し、時刻コマンド「date」の表示を加え、実行結果を視覚的に見やすく工夫することもできます。

# while sleep 1; do clear; echo ---------; date; ls -l; echo ---------; done
---------
Mon 04 Oct 2021 10:09:09 AM JST
total 4
-rw-r--r-- 1 root root 142 Sep 27 11:55 xxx.log
---------

clearコマンドで画面消去するためログ形式で追記されず、
時刻とls -lの実行結果が1秒ごとに書き換えられるように表示されます。

おわりに

今回は基本的なLinuxコマンドを利用して「楽に作業をする」方法をご紹介しました。
複数コマンドを1行に繋げ、オプションやコマンドの使い方を工夫することにより、作業効率は格段にあがります。
皆様もぜひ、様々な方法を試していただき、効率のよい作業を進めていただければと思います。

最後までお読みいただきありがとうございました。

KI
SE部 Helios Group KI
業務で常用しているコマンドを紹介しました。