OREMATOPEE

プログラミング、気になったこと、メモ書き...etc

Linuxの基礎

参考文献

新しいLinuxの教科書

シェルとカーネル

コマンドを実行する部分は、Linuxカーネルが担当する。
CPUやメモリなどのハードウェアを管理するとともに、最終的なコマンド実行を処理するプロセス管理も担っている。

なお、Linuxカーネルは直接人間が操作できるようになっていないので、カーネルのインタフェースとなるシェルが仲介役を担ってユーザーからのコマンドを探してカーネルに実行を依頼し、その結果を受けてユーザーの画面に表示する。

プロンプトとコマンドライン

ホスト名やユーザー名から$%までをプロンプト、以降のコマンド入力部分をコマンドラインと呼ぶ。

[user@localhost ~]$ ls

操作方法

カーソル移動

操作 内容
C + b 後方に1文字分移動
C + f 前方に1文字分移動
C + a 行頭に移動
C + e 行末に移動
M + b 後方に1単語分移動
M + f 前方に1単語分移動

文字列操作

操作 内容
C + h 後方に1文字分削除
C + d カーソル位置の1文字削除
C + w 後方にスペース区切りで1単語分削除
C + k カーソル位置から行末までを削除
C + u カーソル位置から行頭までを削除
C + y 最後に削除した内容を挿入する

画面ロック

操作 内容
C + s 画面表示をロック
C + q 画面表示のロックを解除

コマンド終了、入力のやりなおし

操作 内容
C + c コマンドの強制終了および、入力途中のコマンドの破棄

オプションについて

ロングオプション

--で始まるオプションをロングオプションと呼ぶ。
他のオプションと重複せずに一意に特定できる範囲まで文字列を省略可能。

# --quote-nameを指定したことになる
ls --quote

オプション形式

形式 内容
UNIXオプション ハイフン付きでオプションを指定。ps -aefなど。
BSDオプション ハイフンなしでオプションを指定。ps xfなど。

コピー・ハードリンク・シンボリックリンク

  • コピー
    ファイルを複製する
  • ハードリンク
    ファイルに複数の名前をつけるイメージで、リンク元と同じ内容がリンク先でも表示される。ファイルの実体は1つだがリンク元を消してもリンク先は正常にリンク元のファイル内容を表示できる。
  • シンボリックリンク
    リンク元のファイルを参照できる。ショートカットやエイリアスに近い。リンク元が削除された場合、リンク先は正常にリンク元のファイル内容を表示できない。

基本的なコマンド

findコマンド

ファイル・ディレクトリを検索する。指定した位置から再帰的にディレクトリを掘って探してきてくれる。

-typeでファイル種別を絞り込み可能。

指定 ファイル種別
-type f 通常ファイル
-type d ディレクト
-type l シンボリックリンク

-name-iname(大文字小文字の区別なし)を指定しファイル名で絞り込み可能。
*などのワイルドカードを使用する場合、シェルにパス名展開させないようにシングルまたは、ダブルクオートでオプション引数を囲むこと。

$ find -name '*.txt'

-aオプションでAND検索が可能。

$ find . -type f -a -name '*.txt' -print

locateコマンド

パスが格納された専用のデータベースから指定ファイル・ディレクトリを検索する。そのため、最初だけ手動でデータベースの更新が必要。
findより高速だが、デフォルトでは1日1回だけデータベースの更新をするため、リアルタイムな検索結果が返ってこない点に注意(すでに存在しないファイルが検索に該当する可能性がある)。

導入後、最初にデータベースを更新

# updatedb

通常locateはファイルパスのどこかに指定したパターンが含まれていたら、一致したものとしてみなす。
ファイル名だけにマッチさせたい場合は、-bオプションを使うこと。

$ locate -b python

複数の検索パターンを指定すると、OR検索になる。

$ locate docs document

AND検索を行う場合は、-Aまたは--allオプションを使う。

$ locate -A bash doc

manコマンド

manで対象コマンドのマニュアルを参照できる。

$ man cat

対象コマンドがわからない場合、何をしたいかというキーワードがわかればそれでマニュアルを検索できる。

$ man -k copy

セクション番号

マニュアル名称の後ろにある括弧付き数字は、マニュアルのセクション番号であり以下の内容を意味する番号が付与されている。

セクション番号 内容
1 コマンド
2 システムコール
3 ライブラリ関数
4 バイスファイル
5 ファイルの書式
6 ゲーム
7 そのほかいろいろ
8 システム管理コマンド
9 カーネルルーチン

複数のセクションに同じ名前のマニュアルが存在する場合もあるので、明示的にセクション番号を指定しない限り、小さい番号のマニュアルが表示される。

$ man 1 crontab

特定のマニュアルがどのセクションに含まれているかは、-waオプションを使う。

$ man -wa crontab

whichコマンド

シェルがどのコマンドを実行するかを知りたい場合に使う。
-aオプションでコマンドが見つかったすべての場所を表示してくれる。

typeコマンド

対象コマンドが本当にコマンドなのかエイリアスなのかを確認できる。

$ type ls

エイリアスを無視してコマンド実行

エイリアスとなっているコマンドの前に\もしくは、commandを付与する。

$ command ls
$ \ls

変数

シェル変数

bashなどの内部で使用される変数。数値や文字列を保存できる。 値にスペースを含む場合はシングルまたはダブルクオートで囲み、=の左右にスペースをつけないこと。

$ var1='test variable'
$ echo $var1

シェル変数には特別な意味をもつものがあり、これらを設定することでさまざまな機能のカスタマイズが行える。

変数名 内容
PS1 プロンプト設定
PATH コマンド検索パス
LANG ロケール

など。

しかし実行ファイルとしてファイルシステム上に存在する外部コマンドでは、このシェル変数を参照できず、シェル自体に内蔵している組込みコマンドのみ参照ができる。
外部コマンドはいわばシェルの「外側」で実行されるため、このような挙動になっている。

そのため、LANGなどの外部コマンドで常に設定を反映したい変数は環境変数というしくみを利用している。

環境変数

外部コマンドから参照できる変数。
実は特に明示的に指定しなくても変数LANGなどは、自動的に環境変数として設定されている。

以下で環境変数を表示できる。

$ printenv

自分で設定するにはexportコマンドを使用する。

$ export LESS='--no-init'

権限

所属グループ確認

groupsコマンドで自分が所属しているグループを確認できる。

$ groups

パーミッションの記号と意味

ファイルの場合

記号 意味
r 読み取り
w 書き込み
x 実行

ディレクトリの場合

記号 意味
r 読み取り(ディレクトリに含まれるファイル一覧の取得)
w 書き込み(ディレクトリの下にあるファイル・ディレクトリの作成・削除)
x 実行(ディレクトリをカレントディレクトリにする)

chmodコマンド

ファイルやディレクトリのパーミッションを設定するには、ファイルモードを変更するchmodコマンドを使う。
シンボルモード数値モードによる指定方法がある。

シンボルモード

以下のように実行する。

$ chmod u+w test.txt

chmodのあとは誰にどのような権限を追加・削除するのかを記載する。

  • ユーザー指定
記号 意味
u オーナー
g グループ
o そのほかのユーザ
a ugoすべて
記号 意味
+ 権限を追加
- 権限を禁止
= 指定した権限と等しく

最後は読み取り、書き込み、実行のrwxを記述する。

たとえば以下ではグループとそのほかのユーザーの権限を読み取りのみにしている。

$ chmod go=r text.txt

シンボルモードは指定したパーミッション以外変化しないため、一部だけを変更したいときに便利。(相対的な指定方法)

数値モード

シンボルモードとは対象的に絶対的な指定方法であり、元のパーミッションにかかわらず新しいパーミッションへ変更するときに便利。

rwxの各パーミッションに数値をあて、その合計値で最終的なパーミッションを決定する。

意味 数値
r 4
w 2
x 1

rwxすべて付与する場合は7、読み取りと実行権限だけを付与する場合は4となる。
chmodにオーナー・グループ・その他ユーザーそれぞれに対する数値を合わせて指定する。

オーナーは読み書き、そのほかのユーザーは読み取りと実行を許可する場合は以下のようになる。

$ chmod 755 text.txt

sudoコマンド

suコマンドではスーパーユーザーのパスワードを求められたが、sudoではsudoを実行したユーザーのパスワードを入力する。

suは一度実行すればexitで終了するまでスーパーユーザーのままだが、sudoは一度コマンドを実行すれば元の一般ユーザーに戻る。

sudoコマンドはどのユーザーにどのコマンドの実行権限を与えるのかを設定でき、それは/etc/sudoersファイルで管理されている。
sudoersファイルは<ユーザ><マシン名>=(<権限>)<コマンド>の形式で記述し、<ユーザ>の部分は直接ユーザー名を書くか、%<グループ名>の形でグループを指定する。

以下はwheelというグループ(システム管理を行うグループ)に属するユーザーは、すべてのマシンですべてのコマンドを実行できるという意味。

%wheel ALL=(ALL) ALL

安易にALL設定をするとスーパーユーザーのパスワードを知らなくても管理者権限を行使できるので注意する。

また、このsudoersファイルは書き方を誤ると、sudoが動作せずにどのユーザーもsudoが使えなくなってしまうので、直接エディタで編集せずにvisudoコマンドを使用すること
実行すると特にエディタを設定していない場合はVimが立ち上がり、編集内容に文法エラーがある場合は終了しようとしたときに警告してくれます。
このようにvisudoコマンドを経由してsudoersファイルを編集すると文法チェックを行ってくれるので、単にエディタで編集するより安全に作業ができる。

プロセスとジョブ

プロセスとは

メモリ上で実行状態にあるプログラムのこと。
Linuxカーネルはディスクから実行ファイルを読み出してメモリに格納、その内容に従ってCPUがプログラムを実行する。
プロセスとは、Linuxカーネルから見た処理の単位。
システム全体で一意なプロセスIDという識別番号が割り振られている。

デーモン(daemon)とは

ターミナルに接続していないプロセスのこと。

ジョブとは

シェルから見た処理の単位。
シェルのコマンドラインに入力している1行が1ジョブにあたる。
シェル毎にジョブ番号をもっており、複数のターミナルで2つ以上のシェルを同時に使っている場合、ジョブ番号は重複する。

ジョブの状態遷移

コマンドを実行中にほかのコマンドを実行したい場合、C + zで現在実行しているジョブを一時停止できる。

ジョブの一覧を表示するにはjobsコマンドを実行する。

$ jobs

ユーザーが対話的に操作できるジョブの状態をフォアグラウンドと呼ぶ。
停止状態のジョブをフォアグラウンドにするには、fgコマンドを使用する。
%でジョブ番号を指定しないと、カレントジョブ(jobsコマンドで+が表示されているジョブ)がフォアグラウンドとなる。

$ fg %2

ユーザーが対話的に操作できるジョブの状態をバックグラウンドと呼ぶ。
ジョブを停止すると動作が止まってしまうため、バックグラウンドで動作を継続したい場合は、bgコマンドを使用する。
%でのジョブ番号の指定はfgコマンドと同じ。

$ bg %2

なお、始めからジョブをバックグラウンドで実行したい場合は、コマンドラインの末尾に&を追加する。

$ cp file1 file2 &

ジョブとプロセスの終了

コマンドがフォアグラウンドの場合は、Ctrl + cでよい。

バッググラウンドジョブは、killコマンドでジョブ番号を指定する。

$ kill %2

プロセスを終了する場合も、killコマンドでプロセスIDを指定する。

$ kill <プロセスID>

プロセスを終了できるのはそのプロセスの実行ユーザーのみだが、スーパーユーザーはすべてのプロセスを終了できる。

killコマンド

killコマンドはシグナルを送信しており、プロセスはそのシグナルによってさまざまな振る舞いをする。
シグナル名を省略すると、TERMというシグナルを送信します。このTERMシグナルはTerminateを表している。

シグナルの種類は-<シグナル名>で指定でき、シグナル番号という数値でも指定できる。
以下は同じTERMシグナルを送信している。

$ kill 4695
$ kill -TERM 4695
$ kill -15 4695

シグナル一覧は-lオプションで確認できる。

例外的なシグナルとして、TERMシグナルを受け付けなくなった場合に強制終了する手段として、SIGKILLシグナルが存在する。
これはプロセスへシグナルを送らずLinuxカーネルに送り、プロセスの強制終了を促す。
プログラムの種類によって終了時に現在の状態を保存したりなどの必要処理があるが、このシグナルはそれらを行わせずに強制終了してしまうため注意が必要。

標準入出力

リダイレクト

コマンドの実行と結果の経路である標準入出力を変更する機能のことをリダイレクトと呼ぶ。
Linuxではコマンド起動時に"標準的な"入出力チャネルが開かれ、標準入力はキーボード、標準出力と標準エラー出力は端末ディスプレイに通常は割り当てられている。

標準入力をキーボードからファイルに変更(リダイレクト)したい場合は、<を使用する。

$ cat < /work/file.txt

標準出力を端末ディスプレイからファイルに変更したい場合は、>を使用する。

$ cat /work/file.txt > log.txt

上記では標準エラー出力は端末ディスプレイに表示される。
標準エラー出力のリダイレクトは以下のように2>を使用する。

$ cat /work/file.txt 2> log.txt

標準出力と標準エラー出力をまとめる場合は以下。
2>標準エラー出力&1(標準出力)と同じものへリダイレクトするという意味になる。

$ cat /work/file.txt 2>&1 log.txt

>を使ってのリダイレクトでは、同名ファイルを指定した場合、元の記載内容が上書きされてしまう。
上書きせずファイル末尾に追記する形でのリダイレクトは、>>を使用する。

$ cat /work/file.txt >> log.txt
$ cat /work/file.txt 2>> log.txt

/dev/nullというスペシャルファイルと呼ばれる特別なファイルを標準入出力で使うと以下のような結果になる。

  • 入力先として指定しても何も内容を返さない
  • 出力先として指定しても、書き込んだデータがどこにも保存されずになくなる

よくある使い方としては、エラーメッセージだけ確認したいときに標準出力を空にする方法。

$ ls ./work > /dev/null

パイプライン

標準出力を次のコマンドの標準入力として扱うためのしくみ。

$ ls | less

標準エラー出力もまとめてパイプラインに送りたい場合は、2>&1の記法を使う。

$ ls -l /xxxxx 2>&1 | less

フィルタ

標準入力を入力として受け取り標準出力に出力するコマンドのこと。

# コマンド履歴の先頭10行を出力する
$ history | head

代表的なフィルタコマンド

コマンド 役割
cat 入力をそのまま出力する
head 先頭の部分を表示する
tail 末尾の部分を表示する
grep 指定した検索パターンに一致する行だけを表示する
sort 順番に並べ替える
uniq 重複した行を取り除く
tac 逆順に出力する
wc 行数やバイト数を出力する

シェルスクリプトについて

実行方法

シェルスクリプトの先頭に書いてある#から始まる行はshebang(シバン)という。
スクリプトの実行依頼を受けたLinuxカーネルがこの行を解釈して、#以降に書いているシェル(/bin/bashなど)をつかってスクリプトファイルに書かれた処理を実行する。

実際には下のようなコマンドラインを、シバンを解釈してから実行するイメージ。

$ ./foo.sh
↓
$ /bin/bash ./foo.sh

シェルスクリプトsourceコマンドを使ってカレントシェルで実行することも可能。
ただしカレントシェルで設定したエイリアスの影響を受けたり、その逆でシェルスクリプト内に記述されたエイリアスが実行後もカレントシェルの環境に残ったりするので注意が必要。

なお直接ファイル名で実行したり、シェルの引数として実行した場合に起動するシェルは、カレントシェルから読み出された子プロセスであるサブシェルなので、環境変数は引き継がれるがエイリアスなどの設定は引き継がれない。

シェルスクリプト実行時になぜ./から書き始めるのか

それはシェルがコマンドを実行する際に、コマンドの実体ファイルがあるディレクトサーチパスに、カレントディレクトリが登録されておらず、コマンドが見つからないためである。
サーチパスにないファイルを実行するには、相対パス絶対パスでファイルを指定する必要がある。

サーチパスは環境変数PATHで確認できる。

$ echo $PATH

長いコマンドを1行で書く

シェルスクリプトでは複数のコマンドを;で区切ることにより1行で書ける。

1つのコマンドが長い場合は行末に\を書くことにより途中で改行できる。これはコマンドラインでも使用可能。

$ echo \
>

この>からコマンドの続きを書ける。これをセカンダリプロンプトと呼ぶ。

またパイプライン|の直後にも改行でき、長くなりがちなパイプラインを見やすくできる。

変数の書き方

変数の書き方の注意点

  • =の後に空白を挟まない
  • 変数名はアルファベットと数値と_(アンダースコア)だけ。先頭に数値は使えない。
  • 変数展開した後に文字列連結したい場合などは、${foo}のように波括弧で区切る。
foo=bar
echo ${foo}_baz
  • シングルクオート内の変数は展開できない。

あんまり使わないが、ダブルクオートでも\を使って$そのものを出力できる。

echo "\$foo"

コマンド置換

コマンド置換について

$(foo)のようにコマンドを括弧で囲むことでコマンド実行結果を受け取れる。
バッククオートで囲む記法もあるが、開始と終了位置がわかりづらいのと、中でさらにコマンド置換する場合はバッククオートをエスケープする必要があって不便。

コマンドライン引数

シェルスクリプトではコマンドライン引数を、$1,$2...で受け取れる。
$0にはシェルスクリプト名が入る。
なお、コマンドライン引数に*ワイルドカードを使用すると、カレントディレクトリのファイルが展開されてシェルスクリプトに渡る。

引数の個数は、$#で参照可能。