Linuxについて

#前提

#本題

##Linuxの特徴
###カーネルとユーザランド
ソフトウェアは、基本ソフトウェアと応用ソフトウェアの２つに分かれる。
基本ソフトウェアは、さらに２つに分かれる。

１、カーネル
カーネルはオペレーティングシステムの中核となる部分で、ハードウェアと直接やりとりするなどもっとも中心的な機能を受け持つ部分。
カーネルはハードウェアの違いを吸収して、プログラムがどのようなハードウェア上でも同じように動作する役割がある。

２、ユーザランド
OSが動作するのに必要な、カーネル以外の部分のこと。
ファイルステムやファイル操作コマンド、シェルなどの基本的なソフトウェア群をさす。

###シェル
シェルは入力されたコマンドを理解し、実行する。
シェル自体には大きく２つの機能がある。

１、コマンド入力を受け付けること
２、シェルスプリクトの実行
シェルスクリプトとは、コマンドの入力を自動化するためのもの。
１つのファイルに１つコマンドを１行ずつ記述して作成する。
作成したシェルスクリプトを実行することで、コマンドの実行を自動化することができる。
また、作成したシェルスクリプトをサーバーの起動時に実行したり、数時間ごとに実行したりすることができる。

#基本的なコマンド

##ファイルやディレクトリの参照（ls）

```
#書式
ls [オプション][ファイル]

#オプション
-a
// .で始まる隠しファイル等も全て（ALL）出力

-l
// 長（Long）形式で出力

-t
// 最終更新時間（Time）によって、ソートをして出力

-r
// 逆順（Reverse）にソートをして出力

-la
// 隠しファイルも含めて長形式で表示

-lt
// ファイルの更新時刻順にソートしてリスト表示
```

<code>*</code>は、任意の文字列を示しており、この間に何文字入っても検索結果として出力される。
例）confで終わるファイルリストの表示

```
$ cd /etc
$ ls *.conf
```

<code>?</code>は、ファイル名の文字数がわかっている場合。

```
$ cd /etc
$ ls ???.conf
```

##ファイルのコピー（cp）

```
$ cp [オプション]　コピー元　コピー先

-i
// 処理を行う時にファイルを上書きコピーするかなど確認をする。謝って上書きコピーすることを防ぐために利用される。

-r
// ディレクトリをコピーする。-rオプションをつけると、ディレクトリの中にある全てのファイル・ディレクトリに対してコピーを行うことができる。

-p
// 元ファイルの情報を保存。cpコマンドでコピーすると、新しいファイルはそれらが全てあたらいい内容になってコピーされる。新しい内容を作成せず、古い情報を保持したままコピーを作成したい場合に使用する。
```

##ファイルの移動（mv）

```
$ mv 移動元ファイル　移動先ファイル

-i
// 処理を行う時に確認をする。ファイル上書きなど。

-f
// 強制的に処理を実行。
```

##ファイルの削除（rm）

```
$ rm ファイル名

-i
// 処理を行う時に確認をする。ファイル上書きなど。

-f
// 強制的に処理を実行。

-r
// ディクトリを対象にする。ディレクトリの中の、ファイルやディレクトリも削除する。
```
※Linuxを含むUNIX系OSでは、１度削除したファイルを復活させることはできない。また、rmコマンドは（オプションなしでは）ディレクトリを削除することはできない。

##ディレクトリの作成（mkdir）

```
$ mkdir ディレクトリ名

#オプション
-p
// 指定されたディレクトリの上位ディレクトリも作成する。

#１度で３つのディレクトリを作成する場合
$ mkdir -p dir1/dir2/dir3
```

##ディレクトリの削除（rmdir）

```
$ rmdir ディレクトリ名

#オプション
-p
// 指定した階層までのディレクトリを一括で削除する。オプションをつけないでrmdirコマンドを実行した場合は、最下層のディレクトリのみを削除する。ただし、いずれの場合も対象とするディレクトリ内はからでなければいけない。

#１度で３つのディレクトリを作成する場合
$ mkdir -p dir1/dir2/dir3
```

##ファイル内容を表示（cat）

```
$ cat ファイル名

-n
行番号を付加して表示する。
```

##ページャを使った表示

```
$ more ファイル名

#次のコマンド
スペース　次のページに進む
b　前の一画面に戻る
f　次の一画面に進む
/単語　単語を検索。nキーで検索結果をジャンプ
q　ページャコマンドを終了（quit）

$ less ファイル名

#次のコマンド
スペース　次のページに進む
b　前の一画面に戻る
f　次の一画面に進む
↑　前の行に進む
↓　次の行に進む
/単語　単語を検索。nキーで検索結果をジャンプ
q　ページャコマンドを終了（quit）
```

##ファイルの検索（find）

```
$ find パス -name ファイル名
```

##コマンドのパスを表示（which）

```
$ which コマンド名
```
※コマンドが存在するディレクトリがPATH環境変数に含まれていないと、whichコマンドの結果はエラーとなる。例えば、管理者権限が必要なコマンドへのパスは一般ユーザーでは設定されていないためwhichコマンドでは確認できないことがある。


#正規表現とパイプ

##grepコマンド
grepコマンドは、ファイルの中からデータを検索する。
また、<code> | grep</code>とすることで、標準入力から入ったデータに対し検索を行うことも可能。

```
$ grep [オプション]　検索条件　[指定ファイル]

#オプション
-e
// 文字列を検索パターンとして扱う。

-i
// 検索パターンと入力ファイルの双方で、英大文字と小文字の区別を行わない。

-v
// 検索パターンとマッチしなかった行を選択する。
```

##正規表現

```
#正規表現で使われる記号と意味

^ 行頭を表す
$ 行末を表す
. 任意の一字を意味する
* 直前文字の０回以上の繰り返しを意味する
[...] ..の中の任意の一字を意味する
[^...] ..の文字が含まれないことを意味する
¥ 正規表現の記号をエスケープする
```

```
#正規表現の利用例

^a aで始まっている行
b$ bで終わっている行
a.b aとbの間に１文字入っている
[ab]ab aもしくはbに続く ab(aab,bab)
[^ab]ab aもしくはbで始まらない（not）で、abが続くもの（例：xab,zabなど）
```

#基本的なコマンド２

##ファイルのタイムスタンプの変更（touch）
ファイルには、タイムスタンプ（最終更新日）が必ず存在する。
タイムスタンプはlsコマンドの-lオプションをつけることで確認できる。
その最終更新時間を変更するのが、touchコマンド。
また、指定したファイル名のファイルが存在しない場合、空のファイルを作成する。

```
$ touch [オプション名]　ファイル名

#オプション
-t
// ファイルの更新時刻を指定する。
```

##ファイルの一部の取得（head, tail）

```
$ head [オプション名]　ファイル名

#オプション
-n 行
// 先頭から指定した行を標準出力する。

-c バイト
// 先頭から指定したバイト分を標準出力する。
```
※headはファイルの先頭部分を標準出力する。オプションをつけない場合は、先頭から１０行を標準出力する。

```
$ tail [オプション名]　ファイル名

#オプション
-n 行
// 末尾から指定した行を標準出力する。

-c バイト
// 末尾から指定したバイト分を標準出力する。

-f
// 変更をリアルタイムでモニタすることが可能。
```
※tailは、ファイルの終わり部分を標準出力する。オプションをつけない場合は、末尾から１０行を標準出力する。

##テキストファイルのソート（sort）

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

#オプション
-r
// 逆順でソートする。

-k n
// n列目のデータをソートする。

-n
// 数値としてソートする。
```

###n列目のデータソート（-k）
-kオプションをつけると、ソートの鍵として利用する列の番号を指定する。

```
$ sort -k 2 score
```

##行の重複の消去（uniq）
uniqコマンドを使うことで直前の行と同じ内容があった場合、対象行を出力しない。
連続している同じ内容の行を１行にまとめることができる。

```
$ uniq ファイル名
```

##文字列の置き換え（tr）
trコマンドを使って、標準入力からのデータを文字ごとに置き換える（TRanslate）ことができる。

```
$ tr 文字列１　文字列２
```

##ファイルの比較（diff）

```
$ diff [オプション]　ファイル１　ファイル２

#オプション
-c
// context diff形式で差分を出力。

-u
// unified diff形式で差分を出力。
```

#viエディタ
viでファイルを開いた場合はコマンドモードと言い、ページングによる行やページ単位の移動や、行の削除、コピー、カット、ペーストなどの編集操作を行うことができるモードと文字入力を受け付けるインサートモードがある。

##ファイルを開く

```
$ vi [ファイル名]
```

##ファイルを閉じる
viコマンドを使って開いたファイルを閉じるには、<code>ESCキー</code>を押した後、<code>:q</code>と入力する。
※quitの略

##ファイルを保存する
viコマンドを使って開いたファイルを保存するには、<code>ESCキー</code>を押した後、<code>:w</code>と入力する。
※writeの略

##ファイルを保存して終了する
viコマンドを使って開いたファイルを保存した後ファイルを閉じるには、<code>ESCキー</code>を押した後、<code>:wq</code>と入力する。

##ファイルを保存せずに強制的に閉じる
viコマンドを使って開いたファイルを保存せずに閉じるには、<code>ESCキー</code>を押した後、<code>:q!</code>と入力する。

##テキストの入力
文字列を入力するインサートモードは、コマンドでインサートモードへ切り替える必要がある。
インサートモードへの切り替えには様々なコマンドがあるが、文字列を入力するには、<code>iコマンド</code>もしくは、<code>aコマンド</code>を入力する。
※文字を間違えた時は、DeleteやBSでカーソルの前の１文字が削除できる。

##カーソルの移動
テキストファイルを編集していると、入力間違いに気が付いたり、後からの変更が出てくるので、すでに入力したテキストを修正したい時がある。
追加する文字がある場合は、カーソルを修正したいところへ移動して文字を入力する。

***カーソルの左右移動***
viでカーソルを左へ移動するには<code>h</code>へ下へ、カーソルを右へ移動するには<code>l</code>と入力。

***カーソルの上下移動***
カーソルの上下移動は<code>j</code>へ下へ、<code>k</code>で上へ移動することが可能。

***コマンドを使った行頭への移動***
<code>0</code>コマンドを実行すると、カレント行の行頭へ移動することができる。

***コマンドを使った行末への移動***
<code>$</code>コマンドを実行すると、カレント行の行末へ移動することができる。

##ページ単位の移動
viコマンドは小さなファイルから大きなファイルまでを編集できる。
素早く編集するために画面をページ（デフォルト指定の行数）単位で前後へ移動するコマンドを使う。

次のページへの移動は、<code>「Ctrl」fコマンド</code>、前ページへの移動は<code>「Ctrl」bコマンド</code>。

##行を指定した移動
<code>:</code>の後に行番号を指定する。
例えば、１０行目へ移動したい場合は、<code>:10</code>と入力する。

***コマンドを使った文書への移動***
<code>gg</code>コマンドを実行すると文書頭、つまり１行目へ戻ることができる。

***コマンドを使った文書末への移動***
<code>G</code>コマンドを実行すると文書末、つまり最終行へ移動することができる。

##文字のカット・アンド・ペースト
コマンドモードで実行する。

```
x　１文字削除
dd　１行削除
yy　１行コピー
 nyy　n行コピー　　
p　カーソルの文字の次または次の行にペースト
P　カーソルの文字の前または前の行にペースト　
u　カット、ペーストを１回取り消し（アンドゥ）
```

##行のカット・アンド・ペースト
複数行コピーするには、<code>コピーしたい行数yy</code>のように指定する。

テキストの編集で何か失敗をし、それを元に戻したときは<code>u</code>コマンドを入力する。

##置き換えと検索
巨大で全体像を把握していないファイルはカーソル移動やページ移動のコマンドだけを駆使して目的の位置までたどり着くのは至難の業。
テキストファイルの中にある文字列を検索するコマンドを使うと、素早く目的のいちに移動できる。
また、置き換えコマンドを使えば文章中の文字列を探して別の文字列に置き換えることも素早く行うことができる。

```
/検索文字列　文字列の検索
n　下方向への再検索
N　上方向へ再検索
:対象の行s/検索文字列/置換文字列/オプション　文字列を置換する

#置換オプション
:ns/old/new　　　n行目の最初のoldをnewに置換して終了
:ns/old/new/g　　n行目の全てのoldをnewに置換して終了
:%s/old/new/g　　ファイル全体の検索語句を置換する
:%s/old/new/gc　置換の度に確認を求める
```
※<code>g</code>を指定しないと行ごとに１回だけ置換をする


#グループとユーザ
Linuxを利用するにはユーザアカウントが必要。
任意のユーザでログインするとLinuxを利用することができる。
これはログインしたユーザがLinuxというシステムの利用権限を持っているため。
グループを使えば複数のユーザを束ねることができる。
グループとユーザを適切に設定することで、ファイルやディレクトリ、任意のプログラムやシェルスクリプトなどを必要なユーザにのみ参照・編集する権限や実行する権限を与えることができる。
グループとユーザを作成・変更・削除するコマンドは管理コマンドのため、管理者である<code>rootユーザ</code>で実行する必要がある。

##ユーザの作成

```
$ useradd ユーザ名

#オプション
-c コメント
// コメント（文字列）を指定。

-g グループ名
// プライマリグループ名を指定。

-G グループ名
// 補助グループを指定。

-d
// ホームディレクトリを指定。

-s
// シェルを指定。

-u ユーザID番号
// ユーザID番号を指定。
```

##ユーザアカウントの変更

```
$ usermod ユーザ名

#オプション
-c コメント
// コメント（文字列）を変更。

-g グループ名
// プライマリグループ名を変更。

-G グループ名
// 補助グループを変更。

-l ユーザ名
// 既存のユーザ名を変更。

-u ユーザID番号
// ユーザID番号を変更。
```

##ユーザの削除

```
$ userdel ユーザ名

#オプション
-r
// ホームディレクトリを削除。
```

##グループの作成
複数のユーザの権限をまとめて扱うためにグループを使う。
ユーザは必ず１つ以上のグループに所属していて、主に所属するグループをプライマリーグループと呼ぶ。
最初から用意されているグループに加え、システム管理者が必要に応じてグループを定義できる。

```
$ groupadd ユーザ名

#オプション
-g グループID番号
// グループID番号を指定。
```

##グループの登録情報の変更

```
$ groupmod [-g gid] [-n new-group-name] 変更対象のグループ

#オプション
-n
// 既存のグループ名を変更する場合に指定する。

-g
// 既存のグループIDを変更する。１００未満のグループIDはシステムで使われているため、指定できない。
```

##グループを削除

```
groupdel グループ名
```

##用意されているユーザとグループ
Linuxはインストールしてすぐにそのシステムを利用できるように、ユーザとそのユーザが所属するグループが用意されている。
ユーザやグループは必要に応じて複数追加できる。

###一般ユーザとグループ
Linuxにログインするにはアカウントが必要。
アカウントを作成するとユーザ名と同様の名前のグループが作られ、ユーザはそのユーザグループに所属しているとシステムに登録される。
グループは複数のユーザをまとめるためにある。
個別のユーザを所属部署などの単位でグループ化することができる。
グループを使うことでシステム上にあるディレクトリのアクセス権を設定し、特定のグループに属したユーザのみアクセスできるディレクトリを作成するといった使い方や、特定のグループに属したユーザのみrootユーザになることができるような運用が可能になる。

###rootユーザ
rootユーザはシステム設定の変更や、プログラムのインストールや削除、ユーザを作成・削除することができる、利用に制限がない特別なユーザ。
rootユーザはアクセス権に関係なく全てのユーザのディレクトリへのアクセス、コンテンツの読み書きが行えるなどの点で一般ユーザとは異なる。
このようにrootユーザでログインできれば全ての操作を行うことができてしまうため、rootユーザのアカウントは厳格に管理する必要がある。

###suコマンド
suコマンドはすでに別のユーザでログインしているユーザが、一時的に他のユーザになるためのコマンド。
suコマンドを実行する際、オプションとしてユーザを指定しない場合はrootユーザでシェルを起動する。
オプションをつけずにsuコマンドを実行した場合は、カレントディレクトリを変更せずにrootユーザでログインする。
カレントディレクトリをrootのホームディレクトリに変更してログインするには「su -」、もしくは「su - root」と実行することでカレントディレクトリを変更した上でrootユーザでログインできる。
rootユーザでログインすると、システム管理用のコマンドを実行することができる。
複数人でLinuxシステムを管理している場合は、rootユーザで直接ログインして作業をすると、rootユーザとしての履歴だけ残り、誰がどんな作業をしたのかの履歴が残らない。
一般ユーザからrootユーザへ切り替えると、rootユーザで作業を開始した時間などはすぐにわかる。
安全や管理を考えると、一般のユーザでログインしてからrootユーザの権限を取得し、システム作業することが望ましい。

```
su
su - [ユーザ]

#オプション
su - （もしくはsu - root）
// rootユーザになることができる。

su - user
// 指定したユーザになることができる。
```

##rootユーザでコマンドを実行するsudoコマンド
sudoコマンドを使えば、スーパーユーザ（root）権限でコマンドを実行できる。
普段作業する時はユーザ権限で行えない、必要に応じてsudoを使いコマンドを実行することで、suコマンドでユーザをrootに切り替えることなく、root権限が必要な設定やプログラムを実行することができる。
-uオプションをつけてsudoコマンドを実行すると、任意のユーザでコマンドを実行する。
オプションをつけないでsudoコマンドを実行した場合は、root権限でコマンドを実行できる。
CentOSでは初期設定のままではsudoコマンドは利用できない。
sudoコマンドを使うにはユーザをwheelグループというスーパーユーザ（root）特権をもつグループに登録する必要がある。
sudoの設定は/etc/sudoersファイルを編集することでユーザがsudoコマンドを利用できるようになる。
/etc/sudoersファイルはvicudoコマンドを実行すると編集できる。

```
sudo コマンド
// スーパーユーザ（root）権限でコマンドを実行

#オプション
-u ユーザ
// 指定したユーザでコマンドを実行。
```

#ユーザ権限とアクセス権
ファイル作成者のユーザIDとグループIDがファイルの所有者と所有グループとなる。
所有者と所有グループはファイル情報として重要な属性。
所有者はchownコマンドで変更でき、所有グループはchgrpコマンドで変更できる。

##所有者の変更
ファイルの所有者を変更するにはchownコマンドを使う。

```
chown ユーザ[. グループ] ディレクトリ
chown ユーザ[. グループ] ファイル

#オプション
-R
// ディレクトリを対象にする。ディレクトリの中のディレクトリやファイルを再帰的にたどって変更する。
```
※ユーザとグループを変更するには、rootユーザである必要がある。ディレクトリとファイルは区別なく変更できる。ユーザとグループの区切りに:を使うことも可能。


##所有グループの変更

```
chgrp グループ ディレクトリ
chgrp グループ ファイル

#オプション
-R ディレクトリを対象にする。ディレクトリの中のディレクトリやファイルを再帰的に変更する。
```

##ファイルに設定できるアクセス
ファイルは、ファイルを所有するユーザ、ファイル所有グループからファイル所有者を除いたユーザ、その他のユーザの３つのレベルで権限を設定できる。
ファイルには、ユーザで分けた３つのレベルごとに読み、書き、実行の３つの権限がある。
ファイルのモードを変更するにはchmodコマンドを使う。

```
#例： d rwx rwx rwx

d  rwx       rwx         rwx
   所有ユーザ  所有グループ  その他

#意味
r　読み込み
w　書き込み
x　実行またはディレクトリの移動
```
rwxはユーザとグループとその他の３つに対して指定できる。
rが表示されればファイルの読み込みが可能で、wが表示されればファイルの書き込みが可能。
xが表示されればファイルをプログラムとして実行できるか、または、ディレクトリであればディレクトリへ移動できる。

##アクセス権の変更

```
chmod モード[, モード]... ディレクトリ
chmod モード[, モード]... ファイル
chmod 8 進数表記のモード ディレクトリ
chmod 8 進数表記のモード ファイル

#オプション
-R ディレクトリを対象にする。ディレクトリの中のディレクトリを再帰的に（ディレクトリのなかにディレクトリがあれば、中のディレクトリを全てたどって）変更する。
``` 
ファイルモードを所有ユーザと所有グループとそれ以外のユーザについて設定する。
モード指定の書き方で２通りの記述方法がある。
１、モードの書式を複数書き、カンマで区切って指定。
２、８進数３桁で各ユーザのレベルを指定。

　　　　　　　　ユーザ　グループ　その他
パーミッション　r w x　r w x　　r w x
８進数　　　　　4 2 1　4 2 1　　4 2 1
設定値　　　　　合計値　合計値　　合計値

モードはu（所有ユーザ）、g（所有グループ）、o（その他のユーザ）に対して、r（読み）、w（書き）、x（実行またはディレクトリの変更）を設定したり（＝）、加えたり（＋）、取り消したり（ー）する。
u、g、oの全てに同じ権限を指定するときはaを指定する。

##ファイル作成のモード
ファイルを新規作成すると、ユーザごとに規定されたパーミッションである６４４、もしくは６４４といったパーミッションが設定されてファイルが作成される。
umaskコマンドを使うことで、指定したパーミッションでファイルを作成するように制御できる。

```
umask [８進数のモードのマスク値]
```

#シェルスクリプト
シェルにより入力するコマンドは、シェルスクリプトにより順次実行可能な形式になる。
それを応用することにより、コマンド入力による作業を自動化することが可能。

##シェルとシェルスクリプト
***シェル***
シェルとは、貝殻（Shell）という意味。
カーネルが提供する機能を操作する際に、OSと対話的に操作する必要がある。
シェルはOSの、特にカーネル部分を包み込んでいることからその名があり、対話機能を提供するもの。
シェルはコマンドの入力を受付そのコマンドを実行し、入力したユーザに対しその結果を返す役割がある。

***シェルスクリプト***
/etcディレクトリと/homeディレクトリを圧縮して外部サーバーにコピーするといった流れを考える。

```
# tar cvzf 120626-etc.tar.gz /etc
# tar cvzf 120626-home.tar.gz /home
# scp 120626-etc.tar.gz root@backup.local.example.com ~/backup
# scp 120626-home.tar.gz root@backup.local.example.com ~/backup
```
これを実行のたびに入力するのは面倒。
このような繰り返し行う処理を自動化するための手段としてシェルスクリプトを書いて実行させる方法がある。
system-backup.shという名前のファイルを作成して書き込み、system-backup.shを実行することでファイルに書き込んだコマンドを順に実行する。

```
#!/bin/bash
```

##シェルスクリプトの作成
シェルスクリプトは、テキストで記述する。

```
$ vi lsdate.sh
```
vi上で以下のようなスクリプトを記述し、保存。

```
#!/bin/bash
ls
date
```
・シェルの指定
１行目に#!/bin/bashと記述した。
ファイルの１行目には、利用するシェルの種類とそのコマンド位置を記述する。
２行目以降に実行するコマンドを１行ずつ入力していく。

・パーミッションの変更
作成したシェルスクリプトを実行するには、パーミッションを変更してファイルの実行権限をつける必要がある。
lsコマンドでファイルのアクセス権限を確認する。

```
$ ls -l sdate.sh
-rw-rw-r--. 1 tooyama tooyama 
```
実行権限を付与するためにchmodコマンドを使う。

```
$ chmod u+x lsdate.sh
$ ls -l lsdate.sh
-rwxrw-r--. 1 tooyama tooyama
```
これで所有権に実行権限が与えられた。
実行権限をシェルスクリプトにつけたら早速実行する。

```
$ ./lsdate.sh
```
./というのはパス指定。（カレントディレクトリにあるlsdate.shを実行せよということ）
lsやcpを実行するときは、パスが通っているため、このようなパス指定は必要ない。
今回は、カレントディレクトにある特定のシェルスクリプトを実行させるために、パス指定した。
lsdate.shのなかに記述された、lsコマンドとdateコマンドが順に実行されたことがわかる。

##コメント
コメントとは、プログラム上に書く注釈のこと。
シェルの場合は#で始まる行がコメントとして認識され、プログラムの実行時はコメントは無視される。
コメントは多くの場合、プログラマーが記述したプログラムがどういった処理をするのかを記述したり、一時的に特定の処理を無効化（コメントアウト）する場合に利用する。

```
$ vi lsdate.sh
#!/bin/bash
ls
#date
```
シェルスクリプトを実行

```
$ ./lsdate.sh
```
dateコマンドの出力がなくなったのがわかる。

##echoコマンド
echoコマンドは引数で与えた文字列を標準出力に出力するコマンド。

```
echo [オプション] 文字列

#オプション
-n
// 改行を抑制する。通常の出力は改行されるが、このオプションがあると改行されない。
```

```
$ echo Message test
```

##変数
シェル関数にabcに値を設定し、echoコマンドで内容を確認。

```
$ abc=123
$ echo $abc
123
(abcの内容を表示）
```
変数abcに123を代入。
bashでは、一次元の配列変数を使用することができる。
要素は[]で囲む。
配列変数の内容を表示する場合は、$の後ろに{}で配列変数を囲む。

```
$ abc[0]=123
$ abc[1]=456
$ echo ${abc[0]}
123
$ index=1
$ echo ${abc[$index]}
456
```

***シェル変数と環境変数***
シェルには、２種類の変数がある。
シェル変数と環境変数。
シェル変数は、実行しているシェルの内部でのみ有効。
環境変数は、そこから実行されたコマンド内でも有効。
環境変数は、シェル変数から作成できる。

```
$ export abc
$ export xyz=234
```
１つ目のコマンドではabcという環境変数を作成している。
abcには値を代入していない。
２つ目のコマンドではxyzという環境変数を作成。
xyzには２３４を代入している。次に２つのスクリプトBBB.shとCCC.shを使って、シェル変数と環境変数の動作の違いについて確認する。

```
$ cat BBB.sh
#!/bin/bash
xxx=123                  #シェル変数xxxに123を代入
export yyy=234           #環境変数yyyに234を代入
echo xxx=$xxx in BBB.sh  #変数xxxの値を表示
echo yyy=$yyy in BBB.sh  #変数yyyの値を表示
./CCC.sh                 #CCC.shを実行

$ cat CCC.sh
#!/bin/bash
echo xxx=$xxx in CCC.sh  #変数xxxの値を表示
echo yyy=$yyy in CCC.sh  #変数yyyの値を表示

$ ./BBB.sh
xxx=123 in BBB.sh
yyy=234 in BBB.sh
xxx= in CCC.sh
yyy=234 in CCC.sh
```
yyyは環境変数のため、CCC.shまで引き継がれるため値が表示される。

##readコマンド
readコマンドは、標準入力からデータを読み込む。
すでに変数にデータが入っていた場合、新しいデータに上書きされる。

```
read 変数名
```

```
$ echo $abc
123

$ read abc
aaa
（何か入力）

$ echo $abc
aaa
（シェル変数abcの中身が入れ替わる）
```

##シェル変数
シェル変数の一覧を表示する場合は、setコマンドを利用する。
また削除する場合は、unsetを利用。

```
$ set
BASH=/bin/bash
BASHOPTS=checkwinsize:cmdhist:expand_aliases:extquote:force_fignore:hostcomplete:intera
BASH_ALIASES=()
$ set | grep ^abc
abc=aaa
（abcで始まるシェル変数のみ確認）
$ unset abc
（シェル変数abcを削除）
$ set | grep ^abc
```

#環境変数
現在の環境変数の一覧を表示する場合は、envコマンドを利用。
また登録済みの環境変数を削除するときは、unsetコマンドを利用する。

```
$ env
ABC=999999
HOSTNAME=host1.alpha.jp
TERM=xterm
SHELL=/bin/bash
HISTSIZE=1000

$ env | grep ^ABC
ABC=999999
$ unset ABC
（環境変数ABCを削除）
$ env | grep ^ABC
```

##引用符
シェルスクリプトにおいて、文字列を引用符で囲むことがある。
利用できる引用符には'（シングルクォート）、"（ダブルクォート）、`（バッククォート）があり、使用される引用符により囲まれた文字列の処理が異なる。
シングルフォートで囲まれた文字列のなかに、参照用の「$」付きの変数がある場合、「$」も文字列として認識されるため、変数は展開されない。
タブルクォートの場合、引用符内の「$」付き変数は展開された文字列になる。
バッククォートで囲まれた文字列はコマンドとして解釈され、このとき「$」付きの変数があれば、それを展開した上でコマンドが実行される。

```
$ ABC=123
$ echo 'Value of ABC is $ABC.'
Value of ABC is $ABC.
（$ABCが文字として認識されそのまま表示された）
$ echo "Value of ABC is $ABC."
Value of ABC is 123.
（$ABCが変数として認識され、内容である123が展開された）
$ XYZ=`date`;
$ echo"It is $XYZ now."
（$XYZにdateコマンドの実行結果が入っている）
$ echo "It is `date` now."
（ダブルクォートで全体の文字列を囲み、バッククォートで囲んだdateコマンドを挿入し、変数XYZへの代入を省略）
```

##引数
シェルスクリプトは、実行時にオプションを引数として参照することができる。
引数は$1、$2・・・など$の後に引数の番号を指定することで参照できる。

```
$ cat args.sh
#!/bin/bash

echo '$1:' $1;
echo '$2:' $2;
echo '$3:' $3;
echo '$0:' $0;
echo '$#:' $#;
```

```
$ ./args.sh aaa bbb ccc
$1: aaa
$2: bbb
$3: ccc
$0: ./args.sh
$#: 3
（$1-$3は引数、$0は実行コマンド名、$#は引数の数を示す）
```

##shift文
shiftコマンドは、引数の順序をずらす。
shiftを実行すると、$2が$1に、$3が$2に・・・になる。

```
$ cat argsshift.sh
#!/bin/bash

echo '$1:' $1;
echo '$2:' $2;
echo '$3:' $3;
shift
echo '$1:' $1;
echo '$2:' $2;
```

```
$ ./argsshift.sh aaa bbb ccc
$1: aaa
$2: bbb
$3: ccc
$1: bbb
（$1がbbbに変わった）
$2: ccc
（$2がcccに変わった）
```

##エスケープシーケンス
プログラミング言語には、特別な扱いを受ける文字がある。
例えば、echoコマンドで「Value of ABC is "123".」のように"（ダブルクォート）を出力する方法。

```
$ ABC=123
$ echo "Value of ABC is "$ABC"."
Value of ABC is 123.
（$ABCを""で囲ったが、""が表示されていない）
$ echo "Value of ABC is ¥"$ABC¥"."
Value of ABC is "123".
（表示したい"の直前に「￥」をつけることで"を表示できる。
```

このようにシェルスクリプトでは、¥（バックスラッシュ）はエスケープ文字と呼ばれ、特別な文字で直後の１文字の扱いを変更する。
使用する引用符との組み合わせで、文字の扱いを変えたい場合に有効。
¥（バックスラッシュ）は改行コードにも有効。
¥（バックスラッシュ）を行末に付与することで、文字列の途中で折り返すことができる。
適切に改行を入れることでコマンドの視認性を向上できる。

```
$ echo "I am a cat. As yet I have no name."
I am a cat. As yet I have no name.
$ echo "I am a cat.¥
> As yet I have no name."
I am a cat. As yet I have no name.
```
バックスラッシュによる改行は、シェルスクリプト内でも使うことができる。
バックスラッシュは本来\だが、多くの日本語環境では￥と表示される。

```
$ vi escape.sh

#!/bin/bash

echo "I am a cat. ¥
As yet I have no name."

$ ./escape.sh
I am a cat. As yet I have no name.
```
¥（バックスラッシュ）には、他の用途もあり、次に続く１文字とセットで特別な意味を持つ文字列とする、エスケープシーケンスという手法がある。
よく使用されるものとして、¥t（タブ）、¥n（改行）、¥ooo（oは数字で８進数表記の文字）がある。

```
$ echo -e "I am a cat. ¥nAs yet I have no name¥041"
I am a cat.
As yet I have to name!
```

##sourceコマンド
bashなどのシェルの内部コマンドで、指定されたファイルを読み込んでシェル環境を設置する。
ファイルの内容はシェルコマンドと解釈して実行する。
一般的な用途としては、シェルの環境設定である".bashrc"や".bash_profile"などを設定変更後、ログインし直さずに設定を現在のシェル上で有効にする場合に使われる。

```
$ cat set.sh
（set.shの内容確認）

#!/bin/bash
abc=xyz
echo $abc
```

```
$ echo $abc
（$abcには何も格納されていないため、何も表示されない）
```

```
$ ./set.sh
xyz
（スクリプト内で設定された変数abcの値がechoで出力された）
```

```
$ echo $abc
（変数abcへの値の設定はスクリプト内でしか有効でないため、何も表示されない）
```

```
$ source set.sh
xyz
（スクリプト内で設定された変数abcの値がechoで出力された）
```

```
$ echo $abc
xyz
```

##条件分岐

```
if 条件式1 then ... elif 条件式2 ... else ... fi

#数値比較を行う演算子
a -eq b  aとbが等しい（equal to）ければ真
a -ne b  aとbが等しくなければ（not equal to）真
a -ge b  aがb以上（greater than or equal to）ければ真
a -le b  aとb以下（less than or equal to）であれば真
a -gt b  aがbより大きい（greater than）値であれば真
a -lt b  aがb未満（less than）であれば真
```

##ファイル属性の確認

```
if test -d パス ; then ...
```
-dの部分がファイル属性確認の演算子に当たる。
-dはディクトりであるかの判定を行うため、このif文全体で、パスがディレクトリ出れば真の値を返すという条件式になる。
ファイルの属性確認演算子は以下のようなものがある。

```
-f ファイル名   通常ファイルなら真
-d ファイル名   ディレクトリなら真
-e ファイル名   ファイルが存在すれば真
-L ファイル名   シンボリックなら真
-r ファイル名   読み取り可能ファイルなら真
-w ファイル名   読み取り可能ファイルなら真
-x ファイル名   ファイルが存在して、実行権限があれば真
-s ファイル名   サイズが０より大きければ真
```
なお、testコマンドは[ ]を使って記述することもできる。

```
if [ 条件節 ] ; then ...
if test 条件節 ; then ...
```
ファイルに関する比較演算子は属性以外にもある。
詳細についてはmanコマンドでtestコマンドの項目を参照する。

```
man test
```

##複数の条件を重ねる
***論理積***

```
[ 条件A -a 条件B -a 条件C ] ...
[ 条件A ] && [ 条件B ] && [ 条件C ] ...
```
-aと&&は、それぞれ[ ]の内側か外側かで、使われ方が変わることに気をつける。

***論理和***

```
[ 条件A -o 条件B -o 条件C ] ...
[ 条件A ] || [ 条件B ] || [ 条件C ] ...
```

##一対多の条件分岐

```
if 条件式 then
elif 条件式 then
elif 条件式 then
fi
```
シェルスクリプトでは、case文が用意されており、一対多の分岐が記述できるようになっている。

```
case 変数 in
　　　　　値A）
　　　　　　　　　　　　処理1;;
　　　　　値B）
　　　　　　　　　　　　処理2;;
esac
```
変数の値が値Aの時、処理１が実行される。
最後はcase文の逆からの記述であるesacで終わることが重要。
値はパイプ記号（｜）で区切って複数指定することができる。

```
$ cat case.sh
#!/bin/bash

case $1 in
        a|A)
           echo "引数にaまたはAが入力された";;
        b|B)
           echo "引数にbまたはBが入力された";;
esac
```
これを実行すると

```
$ ./case.sh a
引数にaまたはAが入力された
$ ./case.sh B
引数にbまたはBが入力された
```
またどの値にもマッチしなかった場合の処理を記述するには、値にアスタリスク（*）を用いる。

```
$ cat defaultcase.sh
#!/bin/bash

case $1 in
        1)
           echo "引数に1が入力された";;
        2)
           echo "引数に2が入力された";;
        *)
           echo "1,2以外が入力された";;
esac
```
これを実行すると

```
$ ./defaultcase.sh 1
引数に１が入力された
$ ./defaultcase.sh 2
引数に２が入力された
$ ./defaultcase.sh 0
1,2以外に入力された
```