LPIC 5日目

シェル

これまでコマンドについて色々と説明してきました。そのコマンドを受け付け、適切に表示しているプログラムをシェルといいます。
シェルにはいくつかの種類がありますが、Linuxで標準的に使われているシェルがbashなので本章ではbashで説明いたします。

メタキャラクタ

「特別な意味を持つ文字」のことです。まずはどんなものか見てみましょう。

メタキャラクタ 説明
* 0文字以上の任意の文字列
? 任意の一文字
[] []内の任意の一文字
\ メタキャラクタの打ち消し

これでわかったら凄いですね。
要は、これを使って複数の文字列を一度に表現してみようってことです。
ピンとこないですか?
やったほうが早いかなと思うので、試してみましょう。
/tmp/sampledir があると思うので、それをホームディレクトリにコピーして、そこに移動してください。そこで、

$ ls

1.txt 2.txt 3.txt 4.txt 5.txt a1.txt a2.txt a3.txt a4.txt a5.txt
b1.txt b2.txt b3.txt b4.txt b5.txt c1.txt c2.txt c3.txt c4.txt c5.txt
こんなファイルがあったかと思います。

さて、まずは*を試してみますか。0文字以上の任意の文字、つまり何でもいいってことですね。

$ ls *.txt

どうなりました?結果は自分で確認してみましょう。

次は?を試してみますか。任意の1文字、これはわかりそうなもんですね。

$ ls ?.txt

想像通りでしたよね。
1.txt 2.txt 3.txt 4.txt 5.txt と出たはずです。.txtより前が1文字のものということです。

$ ls [ab]*.txt

[]内の任意の一文字、ちょっと解説すると、、
aかbのどちらか一文字を先頭にして最後が.txtになってれば何でもいいよ。ってことです。

ちなみにこんな使い方も出来ますよ的な

$ ls [3-5].txt

[]内を-(ハイフン)使うことで、範囲を指定出来ます。
これは試さずともわかりますかね。でも結果は自分で確認しましょう。

最後に\です。
文字列としての?を検索したいとしても、?を使うとメタキャラクタ(任意の一文字)として扱ってしまいますよね。それを避けるために\を使います。
使い方は文字として扱いたい文字(例で言うと?です)の前に\を付けるだけです。

メタ練習をしておきましょう

・全てのテキストファイルをメタを使って表示
・abが含まれるファイルをメタを使って表示
・2.txt 3.txtを範囲指定で表示
・1or3が含まれるファイルを表示

 

標準入出力

入り口は一つ:標準入力
キーボードで入力したものだと思ってくれて良いです。

出口は二つ:標準出力、標準エラー出力
プログラムの通常の出力は、標準出力
エラー時は、標準エラー出力

となります。

何やら難しそうに聞こえるかもしれませんが、要はエラー出力先があるんだなと理解してもらえたらOKです。

リダイレクト

$ date > today.txt
$

このリダイレクト(>)は標準出力を任意のファイルに落とすことが出来るものなのです。なので、dateの結果がtoday.txtに落とされたことになり、標準出力には何も表示されません。

追加リダイレクト

$ date >> today.txt
$ cat today
Mon Dec 18 09:17:21 UTC 2017
Mon Dec 18 09:18:00 UTC 2017
$

リダイレクトは全て上書きです。
ファイルに追加していきたいときは追加リダイレクト(>>)を使います。
上記の例は、dateを元々あるtoday.txtに追加したので、dateの結果が2行あるファイルが出来上がっている、ということですね。

標準エラー出力をリダイレクト

$ ls -l sugi
ls: cannot access sugi: No such file or directory
$ ls -l sugi 2> err.txt
$ cat err.txt
ls: cannot access sugi: No such file or directory
$

出力の方法は二つありましたよね、エラーの方をファイルに落とす方法が、上記です。標準エラー出力をリダイレクト(2>)ですね。
自動化されたツール等の場合、エラーを拾っておく必要があるんです。その場合、リダイレクトだと残らないのでエラー出力を取得しないといけません。

リダイレクト関連の確認作業です。難しくないと思いますが、自分でやってみましょう。

・どんなコマンドでもいいので、リダイレクトでファイルを作成してみましょう。
・そのファイルに追加でコマンド結果を残してみましょう。
・エラーになるコマンドを別ファイルに残してみましょう。

パイプ【|】

コマンドの実行結果を次のコマンドに繋げられる、というものです。

$ history | less
 1 sudo yum update -y
 2 sudo yum install -y httpd24 php56 mysql55-server 
 3 sudo service httpd start
 4 sudo chkconfig httpd on
 5 chkconfig --list httpd
 6 ls -l /var/www
:

historyは標準出力なので、コマンド実行だけだと全部出ちゃいますよね。
それを例のようにコマンドを使うと、lessを使ってページ単位で見れる、という事です。
以降でお教えするgrepとの組み合わせで使うことが多いですね。

コマンド履歴

historyじゃないの?って感じですか?
ついさっき叩いたコマンドを探したいのにhistoryと打つのも面倒ですよね。
キーボードの矢印キーの上下(↑↓)で直前の履歴から追うことが出来ます。それだけ。試してみたらすぐわかると思います。

名称補完

コマンドやファイル名・ディレクトリ名はtabキーで補完してくれます。
試しに、hisと入力した状態でtabキーを押してみてください。
historyになりましたよね。
同様の事がファイル名でも出来ます。

$ ls /e
(ここでtabキー押下)
$ ls /etc/

難しくないと思います。
ちなみに、上記の状態でtabキーを2度押すと、候補が一覧されます。

シェル変数と環境変数

変数とは任意の文字列を格納できるもので、シェル変数と環境変数はその適用範囲が違います。
どちらもターミナル(TeraTerm等)からログアウト若しくはexitするまで有効です。

シェル変数

現在実行中のシェルだけで有効な変数です。
設定方法は、変数名=値、です。
表示する際は、echo $変数名、です。

$ sugi=111
$ echo $sugi
111
$

ちなみに、set、で全てのシェル変数を一覧で確認できます。

また、シェル変数にexportをつけることで、環境変数となります。

環境変数

子プロセスでも利用出来る変数です。
先程の例をそのまま使って説明すると、、、

$ export sugi

または、

$ export sugi=222

で、環境変数が設定されたことになります。
ちなみに、全ての環境変数を一覧表示するには、printenv、で出ます。

なんかイマイチわかりにくいですよね。
次の例で確認してみましょう。
bashコマンドで新しい子プロセスが出来るということを理解した上で見てみてください。

$ lysis=000
$ os=win
$ export os
$ bash
$ echo $lysis

$ echo $os
win
$ os=mac
$ exit
$ echo $lysis
000
$ echo $os
(【問】ここで何が表示されると思いますか?)

問の解答はわかりましたか?
bashコマンドで子プロセスが始まっていること、exitでその子プロセスを抜けるということ、それからそれぞれの変数の特徴を読み直せばわかると思います。

一応、答えは、、

win、です。

コマンドとパス

コマンドには組み込みと外部の2種類があります。
組み込みには以下の様なものがあります。

コマンド 説明
cd ディレクトリを移動
echo 引数の内容を表示する
bg ジョブをバックグラウンドで実行する

などなど、興味があれば自分で調べましょう。

外部コマンドですが、これらは実行プログラムが【ある場所】に置いてあり、それを実行しているということになります。
その実行ファイルの置き場所を、which、で調べることが出来ます。

$ which ls
 /bin/ls
$

これはつまり、ls、は実行するときには、/bin/ls、で実行されているということになります。ですので、/bin/ls、とコマンド入力しても結果は同じです。

そうなると、どうやって/bin/配下にあることを見つけてこれるのか?という疑問がわきませんか?
先程のprintenvでもecho $PATHでも構いませんので、PATHの中身を見てみましょう。

$ echo $PATH
/usr/local/bin:/bin:/usr/bin:/usr/local/sbin:/usr/sbin:/sbin:/opt/aws/bin
:/home/ec2-user/.local/bin:/home/ec2-user/bin
$

このパスの中に/binが書かれていますよね。(2つ目)
これらのディレクトリ配下に格納されているファイルについては、絶対パスで指定せずともコマンドとして実行することが出来ます。

locate

この章でやってきたシェルは一旦終わりで、ここからはファイル操作系のコマンドです。
ロケートって読むんですかね?私はコレ使ったことないです。理由はすぐわかると思います。
ファイルを名前で検索したいときに使います。

$ locate ファイル名パターン

パターンとなっているのはもうわかりますよね?メタキャラクタを使うことも出来ます。その際は、引用符で囲む必要があります。例を見てみましょう。

$ locate hosts
(検索結果)
$ locate 'hos*'
(検索結果)
$

 

find【ファインド】

ファイル名だけでなく様々な条件でファイル検索を行う。
locateの上位互換的な存在ですね。findを使っていたのでlocateが必要なかったのです。

$ find [検索対象パス] [検索式]

この検索式で色々な条件が付けれられるのです。例えば、ファイル名とかファイルタイプ(ファイル/ディレクトリなど)とかですね、ワリと使うものを列挙します。

検索式 説明
-name ファイル名を指定
-size ファイルサイズを指定
-atime ファイルの最終アクセス日を指定
-perm ファイルのアクセス権を指定
-type ファイルタイプを指定

試しに、ファイル名で検索してみましょう。

$ find /bin -name "ch*"
/bin/chown
/bin/chgrp
/bin/chmod
$

/bin配下にあるchで始まるファイル全てを検索、ですね。

-exec【ハイフン エグゼック】

-execを付けると、検索して見つかったファイルに対しての操作が出来ます。

$ find [検索対象パス] [検索式] -exec 実行コマンド {} \;

この形は頭ではなく手で覚えましょう。考えて打つもんじゃないです。
まぁコマンドは全てがそうなんですけどね。。

試しに、以下のコマンドが何をするものか考えてみてください。

$ find -atime +365 -exec rm {} \;

 

わかりましたか?
慣れてもらいたいので、こんなのを作ってみましょう。

・ホームディレクトリ配下にある全てのファイルの中から
 【.c】で終わるファイル全てを削除

作ってもそのファイルがないので、削除は出来ないんですけどね。。
あ、ちなみに、その前のコマンドは、「1年以上アクセスされてないファイルを削除」というコマンドでした。

正規表現

コンピューターの世界で文字列を処理する時に避けて通ることの出来ない、とまで書かれていますね。そんな大げさなものではないですが、ちゃんと使えると便利なので覚えましょう。
シェルのメタキャラクタと似ているので、混同しないように注意してください。

メタキャラクタ 説明
* 直前にある文字の0回以上の繰り返し
. 任意の一文字
[] []内の任意の一文字
\ メタキャラクタの打ち消し
^ 行頭
$ 行末

シェルの「?」は、正規表現では「.」です。
シェルの「*」は、正規表現では「.*」(任意の一文字を0回以上繰り返す)です。

簡単な問題を出すのでパターンを考えてみましょう。

・「abc」「a1c」にマッチし、「Abc」「ac」にマッチしない
・大文字のアルファベット1文字にマッチする
・2桁の数字にマッチする
・空行(改行)にのみマッチする
・全てのテキストファイルにマッチする(ドットを含む拡張子を使う)

grep【グレップ】

テキストファイルの内容を検索して、ヒットした箇所やファイル名などを表示します。非常によく使います。オプションもよく使うものばかりです。
grepを知らない開発者はあまりいませんので、覚えましょう。

$ grep [オプション] [文字列パターン] [検索対象ファイル]

一番シンプルに書くと、オプションなしで文字列指定でファイル名指定ですね。以下の様な感じ。

$ grep 1999 wp-login.php
 <html xmlns="http://w3.org/1999/xhtml" <?php language_attributes(); ?>>
$

wp-login.phpファイルの中から、1999という文字列を探した結果、この行が引っかかったよ。という様に読んでもらえればOKです。

オプションについて触れましょう。
まずどんなものがあるのか下記しますので確認してください。

オプション 説明
-F 文字列パターンではなく、文字列として扱う
-c マッチした行数だけを表示
-i 大文字小文字の区別をしない
-l マッチしたファイル名のみ表示
-n 行番号を合わせて表示
-v マッチしなかった行を表示

全てやってみた方がわかりやすいので、やってみてください。
ちなみに、-cとか-lとか-vって使います?って思いませんか。
これらはログ解析したりツールを作るときに使われることが多いかもしれません。-nなんかはデフォルトでそうなるようにエイリアスの設定をしているところの方が多いくらいスタンダードなオプションですね。

あ、あと、grepは(前にやった)パイプと組み合わせることが多いです。要は、何かの一覧を取得してその中から目当てのものを探すという感じですね。

head【ヘッド】

ファイルの先頭部分だけ表示するコマンドです。
デフォルトは10行ですが、行数指定も出来ます。

$ head [-行数] [ファイル名]

catで開くと全部表示されるからうざい、lessとかviだと閉じるのが面倒、ちょっと最初の部分だけみたいんだよね、ってときに使います。

ちなみに、tail【テイル】ってコマンドもあります。
言わずもがな、headの逆です。末尾の部分だけ表示されます。

$ tail [-行数] [ファイル名]

tailはheadより使用頻度は高いかもしれません。
ログを見る時にtailを使うことが多いような気がします。
最新の書き込まれているログだけ確認したいというケースはありますので。

まとめ

メタキャラクタ(シェル/正規表現)、パイプ、リダイレクト、find、grep、と、「っぽい」感じになってきましたね。
特にこの章も理解できないことはないと思いますが、必ず【使える】ようになっておいてください。しつこいようですが、コマンドは体で覚えるもんです。
rmやviと違って、この辺りのコマンドはファイルを壊すようなことはあまりないので、安心して繰り返しコマンドを叩いて、体に覚えさせましょう。
(あ、リダイレクトは壊す可能性ありますね。失礼失礼。)

長く感じる章かもしれませんが、理解を優先させるためにこれでも端折った部分は多いです。このページに書かれている程度の事は完璧に理解してください。