CONTENTS コンテンツ

2021.08.20

catコマンド <=> ファイルを見るコマンド?

こんにちは、Gです。

いまのところ当ブログでGと名乗っている方はいなそうなので、今後もGを名乗っていきたいと思います。

久しぶりにブログ記事を担当します。出来れば今後も時々更新したいとは思っています…!

最近は参画プロジェクトでもプライベートでも、Linux上でCLI操作をすることが多いので、今回はその中でも特によく使われるであろうお馴染みのコマンド『cat』を取り上げて、少し掘り下げてみようと思います!!

 

この記事の対象層

主に以下の方を対象として書いています。

  • ls, cat, cd, cp, mv, grepくらいはわかる!
  • Linuxちょっと触っているけどコマンドのオプション覚えられないから毎回調べながら使っている
  • ファイルを見る?…catでしょ!!
  • catコマンド…あぁファイル見るやつね!!
  • catの名前の由来は”猫”だと思っている

要約すると

『Linuxコマンドを少しは触ったことあるまたは業務に使っている、でもあまり自信はない…くらいの人』

かつ

『暇な人』

向けの記事ということです。Linuxについてそこそこの知識があり、ワンライナーでのCLI操作等に慣れ親しんでいる人からするとあまり感動はないと思います。

 

前置き・諸注意

コマンドやオプションを紹介はするものの解説自体を目的にはしていないので、そもそもコマンド/オプションが分からない方は随時お手元で調べたり、実際にコマンドを打てる環境があれば確かめてみたりしながら見てください…><

※全くのLinux初心者ですという方だとちょっと読んでいくのが辛いかもしれません…。一通り学習してみたあとで読んでみてください。あ、でもわざわざ時間かけてこんな記事読むよりもっと有意義な情報扱っている技術ブログとかUnix系の書籍とか経験豊富な他の先輩とか以下略…

あと、Macだと諸々のコマンドの実装が異なる場合があるので(例:grepなど)、参考にならないかもしれないです。

この記事ではLinux(UbuntuやCentOS/RHEL等の一般的なディストリビューション)を前提としているのでご注意ください。

また、この記事の内容を元に運用した結果について、弊社及び記者(私)は一切の責任は負いません。

 

catコマンドって?

Linux初心者の方は、この『cat』コマンドを学習初期の段階で知ることが多いでしょう。そして多くのWebサイトなどでは

cat … ファイルの中身を見る

と書かれていて、その通りに覚えたのではないでしょうか。

この説明は間違ってはいないですが、catコマンドの本質はそこじゃないです。catはそもそも、”concatnate: 連結する” という英単語が由来であり、複数のファイルの内容を連結して扱うことだって出来ます!

もちろん、単数のファイルを指定しても、その内容を標準出力に返す(→その結果コンソール上でファイル内容が表示される!)ため、『ファイルを見る』を実現する選択肢の1つがcatコマンドであることは事実です。

ファイルを見るためにはcatコマンドを使いますし、catコマンドの実行によってファイルに中身を見ることは出来ます。
①が間違っているわけではないです。

初心者としてはこの程度の知識があれば必要最低限の操作は出来るでしょうし、そういう意味では十分な説明かもしれません。
実際、数行程度の設定値などが記載されたデータを確認したいときはcatでいいです。楽なので。

そして、ここからは主に2つの観点で進めていきたいと思います。

① ファイルを見るためにはcatコマンド以外にも便利なコマンドたくさんある

② catコマンドは純粋にファイルを見る目的以外に大事な働きを持つ

①から確認していきましょう。

 

ファイルを見る目的とcatコマンドの弱点

例えば

  • ファイルの特定の行だけを見たい(すべて出力する意味がない)
  • ファイルから特定文字列の含まれる行だけを確認したい(またその前後行などもみたい)

など、Linux上で作業をするうえでは『ファイルを見る』という操作にもあらゆる目的が想定しうるものです。軽い気持ちでcatコマンドでファイルを見ようとしたら、コンソール上に文字がバーっと流れてきて止まらなくなり、慌ててCtrl + Cを押した経験がある方は多いと思います。私はいまもやります。知らないですけど、Linuxの熟練者もよくやるんじゃないですかね。どうですか?

catコマンドは

  • ファイル閲覧という目的でそのまま単体で使うと、ファイル容量が大きい場合に画面を埋め尽くされる
  • 画面にそのまま出してしまうと検索する、特定の場所に移動する等が出来ない

という弱点があります。そもそも、先に列挙しているように、でかいファイルを全部一気に見る必要ない場合だってあるわけです。部分的に確認できればいい場合もあるわけで。

そもそもcatの働きとして、『ファイル内容または標準入力を』『標準出力に流す』ということをやっているわけで、”cat ファイル”として実行した場合はファイル内容をそのままコンソール上に流すことになるため、このようなことになるわけです。

つまりcatの弱点というよりは、

膨大な量のテキストをそのままコンソール上に流している

この部分を何とかしたいわけです…。

ここからは、先に挙げた①について説明をしていきます。

 

cat以外の選択肢を考える

cat以外に『ファイルを見る』目的を果たすことが出来るコマンドを列挙してみました。時にcatと組み合わせることによって、『ファイルを見る』を実現していきます。先ほど挙げた『膨大な量のテキストを標準出力に垂れ流しにする』を解決する狙いも解決していきましょう。

  1. less
  2. view (vi -R)
  3. head / tail
  4. grep

 

上から見ていきます。

 

less

ファイルを見るという目的を果たす場合、多くの場合ではlessが最適な選択肢になるのではないでしょうか。似たようなコマンドでmoreというものがありますが、moreはlessの前身なのであえて使う意味はあまりないです。

less ファイルパス

として実行すると、画面が切り替わります。
vi(Vim)と近い部分もありますが、初めてだとコマンド操作が難しく感じるかもしれません。

  • g/Gで先頭/末尾に移動出来ること
  • ←,↓,↑,→で自由に移動可能
  • u/d(半画面), f/b(1画面)で上下にスクロール出来ること
  • :nで行ジャンプ出来ること
  • qで閉じること
  • /patternで文字列検索が出来ること

さえ覚えれば、最低限は使えるかと思います。(hで操作ヘルプも見れます)

/に続けて文字列を指定してEnterを押せば、ファイル閲覧しつつ、特定の文字列の検索も可能です。
さらにn/Nでヒットした文字列を順にジャンプしていくことが出来ます!

あとは↓の辺も便利です。

  • F … tail -fと同じくファイルの更新を取り込む(Ctrl + Cで元に戻る)
  • ! … 続けてシェルコマンド(lsなど)を打って実行できる(Enterで元に戻る)

とても自由度が高いコマンドです。是非使いこなしましょう。

 

view (vi -R)

Linux上でファイル編集を行うとき、多くの人はvi(Vim)コマンドを使うと思います。
念のため断っておきますが、ここでは『Vim』のことを指します。本物の『vi』ではなく。現在多くのディストリビューションではviはVimを起動するコマンドとなっています。

Linuxでよく使うエディタとしては,Vim, emacs, nanoなど、まぁ色々あると思いますが、Vimはとりわけ癖の強いエディタとして名高いですよね。しばしばエディタ論争の火種にも…。
私も好きですし、自宅PCのVSCodeにはVimキーバインドを導入しています。多分そういう人は弊社にも多いと思います。

viewは名前通り『見る』コマンドです。vi -Rと打っても同じ動きをします。
これはReadOnly…つまり読み込み専用モードとしてviを実行しています。
書き込みが出来ないので、間違って『:wq』とやって保存してしまう心配もないということです。

※書き込み権限が与えられている場合、!を付けると保存してしまう(:wq!)ので気をつけてください。この辺も設定で変えられるかも…?

もしファイル閲覧のためにviを使っている人がいたら、いますぐview (vi -R)に乗り換えましょう。

1のlessとの違いですが、viewは特定の設定ファイルやスクリプトなどでSyntaxハイライトが効くのが強みです。
(※ただし環境によります)

あとviでお馴染みのコマンドが使えるのがいいですね。

lessと交互で使っていると:qとやらずにqを押してしまいがちなので気をつけてください。

 

head / tail

headはファイルの先頭から数行のみ、tailはファイルの末尾から数行のみ表示するために使用します。
ファイル内容を表示するとき、

  • ヘッダ部分数行が確認できればいい
  • 後から追記された情報だけ確認できればいい

というようなケースでは、これもファイルを見るための選択肢になるでしょう。

例えば、ログファイル(tekitou.log)の末尾30行だけ取得したいなら

tail -30 tekitou.log

で済みます。

設定ファイル(tekitou.conf)の先頭部分10行だけ確認したいならば

head tekitou.conf

どちらもオプション –で行数を指定出来ますが、↑のheadの例のように省略すると10行となります。

 

また、これらを組み合わせると少し器用なことも出来ます。

例えば、あるファイル(ファイル名: confidentialとする)の100行目から110行目あたりに知りたい情報が記載されている(ことが事前にわかっている)としたら、

head -110 confidential | tail -11

として、100-110行目の情報を取得できます。
先頭110行を取得して(パイプをつないで)tailで110行を後ろから11行分取得して出力しています。
(SQLでいうlimit … offset …/offset … fetch …のような使い方でしょうか)

特定の文字列を含む行を出力したい…なら後述のgrepが優秀ですが、特定の行に記載された情報を知りたい場合には便利かと。

また、先ほどlessのところでも触れましたが、tailは-fオプションを付けることでファイルの更新を取り込みながら表示することが出来ます。ログ監視などでお馴染みのコマンドですね。

後述のgrepと合わせて特定のメッセージだけ抽出することが出来るのも強みです。

e.g. ログファイル(nanika.log)にERROR文字列が現れた場合、随時取り込んで表示する

tail -f nanika.log | grep --line-buffered 'ERROR'

 

grep

GNU系コマンドで私が一番好きなコマンドです。今度これだけで記事書きたいですね…。

(MacだとデフォルトがBSD版とのことなので、諸々の挙動が違うかもしれません。知らないので言及しません)

 

grepは検索したい文字列であったり、その値が記載されたフィールドがはっきりしている場合に有効です。

由来は、ファイル全体から正規表現に一致する行を表示するという意味の

global regular expression print

です。(引用元:wiki)

grepという英単語があるわけではないです。ちなみに私は最初聞いたとき、『Grasp:把握する』という英単語を思い浮かべました。

 

grepは、あらゆる場面で非常によく使われているコマンドです。指定したパターン文字列を含む行をすべて抽出して出力します。

単体での使用はもちろんのこと、あらゆるコマンドと入出力をパイプ(|)で繋げて使用することも多いです。

regular expressionとありますが、正規表現を使わずとも検索できます。デフォルトでは正規表現が有効なため、”.”, “\”などの特殊な意味を持つ文字そのものを検索する場合は”\”によるエスケープ処理が必要になります。えぇ面倒ですね…。

その場合は、便利な”-F”というオプションがあり、エスケープ不要でリテラルとして文字列の検索を行います。また、通常のgrepより高速です。

同じ用途でfgrepというコマンドもありますが、『互換のために残された非推奨コマンド』らしく、基本は”grep -F”で良いでしょう。ディストリビューションによってはaliasだったりgrepを実行するシェルスクリプトだったりします。

また、リテラルでの検索の場合であっても、”>”や”!”などはシェル上で特殊な文字として解釈されてしまうため(grepに渡される前にシェルが処理をしてしまう)、パターン指定にはシングルクォーテーションを使うのが良いです。例えばシェルスクリプト上でパターン内に変数を組み込みたい場合等は、ダブルクォーテーションを使いましょう。

 

巨大なファイルのある特定の部分が見たい、なら最初からgrepでいいでしょうということです。
例えば、あるログファイルからエラーメッセージだけ確認したい、であれば、

grep -i "ERROR" aru_logfairu.log

でよいと。(iは大文字小文字を区別しないというオプション。ignorecaseの略)
その前後とか含めて調べる必要があればless/viewで検索をして見てみるのが良いですが、grepは-A,-Bオプションを使うとヒットした行の前後(-An … 後ろn行 / -Bn … 前n行)も表示できるので、
特定の行の前後10行などを表示することなども可能です。ABを省略して-10などとすれば前後10行を指定できます。

ところで、A、Bの並びをみるとAが前、Bが後ろに感じませんか?逆なので気をつけてください。
(※A/Bはafter/beforeの略です)

grep -10i "ERROR" aru_logfairu.log

grepは特によく使う基本中の基本コマンドなので、すべてのオプションを正しく理解して使いこなす価値があると思います!!

エンジニアの方は、Win環境においてもサクラエディタやVSCodeなどGUIで”Grep操作”をやることが多いことと思います。しかし、grepコマンドそのものを極める(さらに正規表現をくまなく使いこなす)ことにも大きな価値があるかと!!
Win上でも、GNU Grepは使えるようにしておくと何かと便利です。Win上にGitを入れていればコンソール(Git Bash)上から使えると思います。TeXなどのツールに含まれている場合もあります。

余談ですが、Winのコマンドプロンプトでのコマンド『findstr』で使用できる正規表現はかなりプアーです。
Win上で新たにツールを導入せずにGrepと同じことをやりたければ、PowerShellで『Select-String』を使いましょう。

 

次に、特定行の抽出ではなく、特定行のみを除外したい場合、
e.g. あるスクリプトファイル(fuga.sh)のコメント行(#から始まる行)を出力したくない

grep -v '^#' fuga.sh

でオッケー!-vオプションは指定したパターンに合致した行を、出力から除外します。
ファイルを見るにしても、不要な情報は最初から削ってしまえばいいわけです。

それでもボリュームがあり、そのなかでさらに情報を吟味したい場合(検索したり前後を調べたり等)なら、その結果をlessに渡してしまいましょう♪

grep -v '^#' fuga.sh | less

その後はg/G/f/b/u/dなどで行き来しつつ、/strで該当箇所を検索するなど。

また”| grep”と繋げて、除外をしたなかから更に特定のメッセージを切り出すなど。
grepでは’^A && B’(Aではない、かつBである)のようなことが出来るわけですね!!

例えば、コメント行ではない行でdebugという語句を含む行を出力したければ、

grep -v '^#' fuga.sh | grep debug

ちなみに’^#’この指定は先頭が#の場合のみマッチします。^は行頭を意味するため。
半角スペースやタブ文字等によるインデントが入っていると、その行はマッチせず、除外されません。
それじゃ困るという場合は、以下のように指定しましょう。

grep -Pv '^\s*#' fuga.sh

ついでに空行も消したいという場合は以下で。

grep -Pv '^\s*#|^$' fuga.sh

Perl正規表現(grepオプション:-P)で、’\s’は空白文字を表すメタ文字です。
*は直前文字0個以上の繰り返しなので、#前に空白があってもマッチしてくれます。逆にコメント行だけ確認したければ、vを取りましょう。

perlは多くのメタ文字が使えることに加え、先読み/後読みなどとてもリッチな正規表現に対応しているので、これもまた覚える価値が大きいです。

 

その他の選択肢

以上、1~4で紹介したコマンド以外でもnl, cut, tac, sed, awk, perl, split, trなど、ファイルを見る、さらに必要な情報を整形/抽出するためのLinuxコマンドはたくさんあります。

例えば、ずらっと,区切りの超長い行を持つファイルを整形したければ

tr "," "\n" ファイル

とすれば見やすく出来たり…。見るためには部分的に文字列を加工したっていいわけです。

ファイルを見るからは少し外れますが、以下のコマンドを打ってみると便利さが伝わるかと思いました。

e.g. 環境変数PATHを見やすく改行区切りで表示して確認してみる

echo $PATH | tr ':' '\n'

ファイルを見る際にも、

cat ファイル | tr 'a'  'b' | less

とすれば、ファイルの一部分を都合よく整形したうえでlessにバトンを繋げられたり…小テクとして役立つこともあります。

他にもcsvなどで特定のフィールドの値でソートしたい場合はsortコマンドを使う、重複値を省く場合はsort | uniqを使う、複雑な置換がしたければsedを使うなど。

選択肢が増えるとLinux上でのCLI操作も楽しくなってくると思います。

Linuxコマンドは1つ1つ最小限の目的を果たすために設計されています。
これらを細かく組み合わせることで、非常に多彩な操作が可能になります!!

シェルスクリプトを書く際やワンライナーでやりたい操作を実現する際、この考え方がとても生かされてくると思います。

 

まとめ

大変くどいようですが、結論として言いたいことは…

ファイルを見る → cat

ではなく

選択肢はたくさんあるのでそれらについて知り、状況に応じて上手に使い分けられるようにしよう!そして、時には複数のコマンドを上手く組み合わせてみよう!

ということです。

あと誤解されぬように言うとすれば…、

catコマンドが悪いのではなく、catコマンドの使い方が悪い(巨大ファイルを標準出力に垂れ流し)

です。この辺は次回掘り下げていくところでもありますね。

 

また、冒頭にも触れましたが、数行程度の軽いファイルならcatで全然いいです。2,3行の設定値を持つファイル等にlessやgrep使ってもしょうがないわけで。

目安としては、1画面を超える程度の量になるとlessを使用するのがいいかなと!CLI上で前回の実行コマンド見えなくなったら嫌ですからね…。

 

catに限らず、やりたいことと、それを実現するコマンドというのは、必ずしも1対1対応するわけではないということを伝えたかったです。

 

 

最後に

実はメインとして書きたかったのは①ではなく②の話なのですが、書き出してみたら思ったより長くなってしまったため(grepのせい)、次回に回させていただきます。

今回は『ファイルを見る選択肢はcatだけじゃない』という話でした。次回は『catはファイルを見る以外に重要な使い方がある』という話です。

技術系記事に慣れておらず脱線を繰り返し、あまりまとめられていないのですが…ここまで読んでくれた方、本当にありがとうございました。少しでも役立てればと思います。この記事に関連する(質問|ダメだし|誤記指摘)あれば、何でも答えますのでお気軽にどうぞ。

それ以外の質問は、 /dev/null にリダイレクトします!!

 

(これが言いたかっただけ)

 

 

半年間ほどのLinux CLI操作経験を思い返しながら書いてみましたが、あまり実務っぽくないような例もあるかと思います。説明の都合で敢えてそう書いている場合もありますが、今後はより実践経験を積んで説得力を高めていきたいと思います。

ここ最近はUnix系の本を特によく読んでいたので、そういった本から影響を受ける部分もありました。本で学んだことを実務に生かしてみたり、実務で知ったことと本の内容を比べてみたり、暇なときワンライナー書いて遊んでみたり…
ちなみにいまは、C言語でUnix系コマンド作ってみよう的な本を読んでいます。

近いうちにきっと②についてもまとめてみます。では。