初心者と読み解くUNIX

# この記事の内容
UNIXをちゃんと知ろうと思って初心者が本を読んだのでアウトプットと備忘録という目的で書きました。

この記事は
- Linux、触ったことあるけどよく知らない
- UNIX知らない
- 基本コマンドをしっかり知りたい
という方におすすめです。


## UNIXとは
### UNIXの歴史
UNIXは、コンピューターのOSの一つで、更に言うとマルチタスク・マルチユーザーが使えるOSです。
UNIXはAT&Tベル研究所で誕生したOSです。
最初、Multicsという多機能OSが作られましたが、多機能な分OSが大きくなりすぎて当時のコンピュータでは動かず失敗に終わりました。
ここで、Multicsの開発に携わったケン・トンプソンさんがこの失敗からUNICSというOSを作成しました。MultiからUni（単独）という言葉に変わったように、UNICSはとてもシンプルなOSとして生まれ変わりました。のちにUNICSからUNIXへ名前が変わっていきます。

ベル研究所は19xx年代にて世界最先端の研究を行ってきた研究所で、数々のものを開発してきました。UNIXのカーネルもC言語で書かれるようになるなどバージョンアップの上、UNIXはSystem Vに進化しました。
（一方、UNIX開発者の一人トンプソンさんはベル研究所を休職し、カリフォルニア大学に行きそこでBSD(BerkeleySoftwareDistribution)を作り上げました。）

こんな過程を経て完成したUNIXは、今でも大部分のOSのもとになっています。

### Linux
そんなUNIXですが、ソースコードとして公開されていたため様々な派生版UNIXが誕生しました。企業もシェアを取るためUNIXマシンを製造していましたが、当時はライセンス関係の問題で企業の争いが相次いだそうです。
（この間にMicrosoft Windowsが誕生し圧倒的シェアを得ました。ちなみにWindowsはUNIXではありません。MS-DOSというOSがもとになってできたものです。Microsoftももとは派生版UNIXをリリース(Xenix)してこの戦いに参加してはいたらしいですが、MS-DOSとはまた別物）

1991年ごろ、リーナス・トーバルズさんが学校の授業で渡されたUNIXの機能が不足していると感じターミナルエミュレータを自力で作成（改造）したのをきっかけに、OSをゼロから作り直したのがLinuxです。（この方はGitも作った方）
UNIXソースコードを使わず１から書き上げ作ったそうですが、UNIX標準規格(POSIX)に沿ってるので操作する側からは相違点は感じない作りになっています。よくLinuxはUNIX"系"と書かれますが、これはUNIXライク・UNIX風に動くというとこから来てるので、正確にはUNIXではないです。

UNIX OSはライセンスで縛られ扱いにくい点、Linuxはオープンソースなので自由にカスタマイズもできるため大きく普及しました。

Linuxは厳密にはカーネルであり、これに必要なアプリケーションを各自でまとめたものをLinuxディストリビューションといいます。
iPhoneは知らないですがAndroidだと機種によって入ってるアプリが違ったりしますよね？あんなもんだと思っていればいいと思います。Androidではあるので電話アプリの仕様が違えどインストールして使えますよね。

定番なLinuxディストリビューションはRed Hat / Debian / Slackware系があります。
ubuntuはDebian系ディストリビューションのOSです。
なにが違うんかというと、よく使うのではパッケージ管理システムがrpmやaptやyumだったりする点です。


### 起動
起動する際は、直接UNIXを動かすのではなくまずブートマネージャーが起動されます。
一般的なのはGRUB(GRand Unified Bootloader)というブートマネージャーです。
パーティション分割してデュアルブートをする際などに触れる機会があるかと思います。

## UNIXシステム（本題）
### マルチタスク
GUIを使うと当たり前に感じますが、複数のアプリを立ち上げて同時に表示したりとかよくありますよね。（Chromeで調べながらアプリインストールしたりとか）
UNIXシステムはCUIがベースなのでこんな処理できるのかと思いますよね。
前述の通りUNIXはマルチタスク・マルチユーザーOSなのでもちろんできるようになっています。

それを実現する方法がUNIXにはあります。
#### バックグラウンド処理
コマンドの後ろに & をつけるとバックグラウンドで処理されます。
#### 別のコンソールで処理
UNIXシステムには、マルチタスクを実現するために複数の仮想端末を用意しています。これは仮想コンソールと呼ばれるもので、複数存在します。これがあることでマルチタスクを実現しています。

デスクトップ版ubuntuだとターミナルを複数開くことで実現できますが、コマンドラインだけのUNIXではこうしてマルチタスクを動かします。
というより、LinuxもUNIX系なので同じ処理になっているはずです。ターミナルを開いて消してを繰り返すことでもコンソール(tty)の番号(tty1とか)が変わることで仮想端末も一緒に変わってることがわかると思います。
```sh:tty(仮想コンソール)の確認方法
ps x | grep tty
```
また仮想コンソールは ` Alt + F2 ` で切り替えられます。

### シェル
shだけでなくbash,zshなど複数のシェルがありますが、使われているディストリビューションによって変わるので確認するには ` $SHELL ` で確認できます。
シェルの変更は ` chsh `です。

・シェルとは
正確な意味でのLinuxはカーネル(狭義のLinux)と書いたように、その本体のLinuxを操作するためのプログラムです。
Pythonなどのプログラミング言語を使う際には、Pythonという言語で書かれたプログラムがLinuxの提供する機能を使い処理をしてそれを表示するという形なのはわかると思いますが、Pythonじゃなくてシェルというものを使うという解釈でとりあえず大丈夫だと思います。
厳密には実行ファイルまではPythonというアプリケーションがやって、それ以降をカーネルに投げるので手間が増えるが、まあ気にしなくていいでしょう()

### マルチユーザー
ユーザーはroot(管理者)と一般ユーザーからなります。
一般ユーザーは` useradd `というコマンドで複数のユーザーが作れます。
また` su `で現在ログインしているユーザーからの変更もできます。ユーザーを変更する際は` su -l [user] `とオプションをつけることで変更するユーザーのパス・カレントディレクトリ・ログインシェルに同時に変えられます。（逆につけないと現在のユーザーのパス等がそのまんまなので、もしrootに昇格するときに-lオプションをつけないとrootの$PATHが通らない）

グループなども作れて、個人またはグループで閲覧できるファイルなどの制限もつけることができます。


### ファイルの操作
ここからはUNIXのコマンド操作についても解説します。UNIX系でも使える基本的なものなのでぜひ覚えてみましょう。

- ファイル操作
ファイルを作る・書き込む
```bash:ファイルを作る
touch [filename]

# echo (リダイレクトを使う（後述）)
echo 'aaa' > [filename]
# cat (同様)
cat > [filename]
# cat ではこの後に文字を書いてCtrl-Dで終了
```

- ファイルを検索する
```bash:ファイル検索
find [基点ディレクトリ] 検索条件 [アクション]

# 検索条件にはいろいろあるが、-name [ファイル名]で指定ファイルを検索
# アクションには表示方法を指定できる
```
そのほかlocateと、コマンドを検索するwhichというコマンドもあります。

- アーカイブの作成
複数のファイルを一つにまとめることをアーカイブと言います。
アーカイブにはtarコマンドを使います。
たくさんのオプションがあるのでよく使うのを記しておきます。
    c : アーカイブする
    x : 展開する
    f : ファイルを指定
    r : あるアーカイブに追加する
    t : 内容を見る
…などがあります。これらはコマンドex)ls -lのようにハイフンで指定せず、またくっつけて組み合わせて使います。
```bash:アーカイブ保存
tar cvf files.tar file1 file2
```
これは、file1,file2というファイルを files.tarという名前でアーカイブするという意味です。

tarコマンドは圧縮・解凍にも対応しており、compress形式とgzip形式ならばtarにてgzipならz,compress形式ならZのオプションを加えればOKです。
```bash:アーカイブを圧縮して保存
tar zcvf files.tar.gz file1 file2
``` 


- ディレクトリ操作
これはよく使う、cdコマンドでディレクトリを変更できます。

プログラミング内などで一時的にディレクトリを移動したい時は
pushd [ディレクトリ名]コマンドで一時的に移動、
popdコマンドで戻る
という感じのコマンドがUNIXには用意されています。


加えて、ディレクトリを作成するのに使われるmkdirですが、オプション-pをつけると二段構成にしたいときなどに勝手に足りないディレクトリも作ってくれます。

例 : /home/hoge が現在のディレクトリとして、/home/hoge/dir1/files/ というフォルダを作りたい時、` mkdir -p ./dir/files `とすれば一発でいけます。
（これを知らないと、` mkdir ./dir `として` cd ./dir ` から ` mkdir ./files `とする必要があります。）


### テキスト操作
今のUNIXにはviというテキストエディタが標準搭載されています。ですがただ内容を見たい時などにはわざわざエディタを開くのは面倒。そんなときのためのコマンドもいくつかあります。

` cat `コマンドはよく使われますね。オプションで-nをつけると行番号も表示できます。
また` view `というコマンドではviを読み込み専用として起動します。

これらは数十行なら一画面に収まって表示できますが、アプリのソースファイルなどは数百行以上あることもざらです。こんなファイルをcatで開いても後ろの数行しか見えないしわざわざスクロールするのも面倒です。
こんなときは` more [option] ファイル名 `というコマンドを使えます。
オプションには
-s : 空白行が続くときは1行にまとめる
-c : 次ページを表示するときは画面をクリアにする
+(行番号) : 指定した行番号を表示
などがあります。またmoreコマンドはviのように内部でまたコマンドが使えます。
具体的には、` Enter `で次の1行を表示・` スペースキー `で次の一画面・` b `で前の一画面...などです。(終了は` q `)

同様に` less `というコマンドもありますが、これは` more `の拡張版で基本は同じです。いろんなことができるので詳しい使い方はここでは端折ります。一つだけ違いを挙げると、`more`では最終行までいくと終了しますが、`less`はそのまま表示モードでページを戻ることもできます。

何百行もあるテキストファイルといえど、moreはめんどいって
って人向けに、先頭・末端の部分だけ表示するコマンドもあります。
```bash:先頭もしくは末尾を表示
# 先頭
head [-表示する行数] ファイル名
#行指定のない場合は先頭の10行表示されます。

# 末尾
tail [option] ファイル名
#オプションには
#-[行数]で最後から指定した行数を表示
#+[行数]で指定した行数から表示
```

tailコマンドでは、+[行数]で表示させた場合普通にcatと変わらないことがあります。
どんなときに有効活用できるかというと、x行目からy行目などと部分指定したいときに使えます。
```bash:行数指定
tail +13 file.txt | head -5

# -> 13行目から5行後(18行目)まで表示
```


- テキストの検索
テキストの検索には` grep `がよく使われます。
これはよく使うので詳しく解説している方のを参考にしてください。（初心者わいはうまく説明できないので）

grepの説明：https://qiita.com/yagiryu/items/6128ad998560510be5de
正規表現の説明：https://www.tohoho-web.com/perl/regexp.htm


- テキストの比較
テキストファイル同士の比較するコマンドがあります。

以下で使うファイルの中身を
ファイル1 :
aaaaa
BBBBB
CCCCC
ファイル2 :
AAAAA
BBBBB
CCCCC
とします。

```bash:テキストファイルの比較
diff [op] ファイル1 ファイル2

# 出力は以下のようになります。
#> 1c1
#> < aaaaa
#> ---
#> AAAAA
#> >

```

出力は謎の記号とファイルの一部の文字というよくわからない結果になりましたね。
最初に出てきた "1c1" とはなんでしょうか。
` diff `コマンドは「どうすればファイル1がファイル2と同じ内容になるか」を表示してくれるもので、"1c1"は意訳すると「ファイル1の1行目を変えるとファイル2の1行目と一致するよ」ということを表しています。

この意訳からも想像つくと思いますが
最初と最後の1はファイル1,ファイル2の行数をそれぞれ表しています。
真ん中の'c'は処理方法を表します。
表示される文字はa,c,dのどれかで、aは「追加」・cは「変更」・dは「削除」を表します。（add/change/delete）
10d8と出た場合、「ファイル1の10行目を消すとファイル2の8行目と一致する」といった具合です。ディレクトリの比較もできるのでよかったら検索してみてください。

- テキストファイルの一括編集
並び替えや置換などができるコマンドがあります。
便宜上、以下で使うファイル1の中身を決めておきます。
```bash:ファイル1.txt
a 1
b 6
c 3



d 9
a 1
```


` sort `コマンドでは数字を昇順で並び替えたりできます。整理されたCSVデータなんかをこれで並び替えることもできます。
オプションを組み合わせて目的の順に並び替えます。一部だけ紹介すると
-r : 逆順で並び替え
-k [指定] : 場所と並び替え種別を指定します。「-k 2」とすれば2列目の数値で並び替えるという意味です。
-t [文字] : 区切る文字を指定します。デフォルトでは空白文字になっていますが、CSVファイルなんかだと','で区切られているので、その場合はこのオプションで指定します。
つまり、ファイル1.txtにsortで並び替えるとき
```bash:並び替え
sort -r -k 2 ファイル1.txt

# 出力
#> d 9
#> b 6
#> c 3
#> a 1
#> a 1
#> 
#> 
#> 
```

` uniq `コマンドでは重複行の削除を行います。
基本は1行ごとに重複を見ますが、-fオプションで列を指定して列の重複検索しを削除します。
```bash:重複
uniq ファイル1.txt

# 出力
#> a 1
#> b 6
#> c 3
#> 
#> d 9
#> a 1 
```
空白行が重複しているのですこし短くなりました。ただ、ファイル1のもとの内容を見るとわかるかと思いますが、"a 1"は重複してるのに削除されてないですよね。
uniqは離れて重複している行は取り除かれないのです。
そのため、よくsortで整列してからuniqで重複を取り除く二刀流でつかわれます。


` tr `は文字の置き換えに使います。
引数にファイルを指定できないので、リダイレクトで渡します。
```bash:文字の置き換え
# tr [置き換える前の文字] [置き換えたい文字]
tr a A < ファイル1.txt
```
ちょっと長くなるので出力は書きませんが、aがAになっていると思います。


### システム管理
システム情報などの確認や管理に使えるコマンドたちです。ダイジェストで書いていきます。
```bash:システム管理コマンド一覧
# システム情報の確認
uname [option -a:すべて確認]

# ログイン中ユーザーの確認
w
# 稼働時間（wコマンドの一行目）
uptime

# ユーザーのログイン履歴
last [user（特定のユーザーだけ見たいならここで指定）]

# CPU使用率
top
# メモリ使用状況
free
# ディスクの空き容量
df
# ファイルのディスク使用状況
du [option] ディレクトリまたはファイル名

# プロセスの確認
ps
# 因果関係も表示
pstree
```


### 便利なコマンドたち
覚えておくと便利かもしれないです。

- コマンド履歴の表示
` history [表示数] `でコマンドの履歴を表示できます。

- エイリアス
リンクなどで使われますが、オプションを含めたコマンドも定義できます。
たとえば、ディレクトリを表示する` ls `コマンドですが、常にすべての情報を出すようにしたい時（すなわち` ls -l `）はエイリアスを定義することで常に` ls `を実行すると` ls -l `と等価な動きをします。
```bash:エイリアス
alias 定義名 = 定義

# 上の例でいうと
alias ls = 'ls -l'
# 普通のコマンドでも省略したいときとかにも使える
alias hs = history
# ->hsを実行でhistoryコマンドが動く
```
定義したエイリアスは` alias `で確認できます。
削除するときは ` unalias 定義名 `で削除できます。全部消したい時はオプションとして-aをつけます。

上で書いたようにlsを'ls -l'と定義すると、以降lsはオプションを含めたものを返します。ただときたまlsだけの機能を求めることもあります。
このときはバックスラッシュ(\)をつけてlsを実行すると、素のlsが呼び出せます。(エスケープシーケンスとは別？かはわからないです)

aliasはログインしている間のみ有効で、ログアウトやPCを再起動するとすべて消えます。常に使いたい場合は` .bashrc `などの設定ファイルに記述します。


## シェルのあれこれ
最初のほうに述べたのとおり、シェルをPythonなどのプログラミング言語と同じようなものと考えると、シェルもプログラムを動かすことができるはずです。

### リダイレクト
基本、コマンドなどで出力される文字などは標準出力に渡されます。これをファイルに書き込みたいなどしたいときにリダイレクトを使います。
` > ` 1つで出力先に上書きします。
` >> `2つだと出力先に追加します。（上書きではなく）
エラー出力も標準エラー出力に出力されるので、これも変更できます。
` 2> `でエラーの出力先も変更できます。上書きされます。（` 2>> `とすると追加）
` 2>& `とすると、エラーと標準出力を一緒のファイルに保存されます。

リダイレクトはwindowsも使えます。

### シェルスクリプト・制御構文
シェルはPythonなどのプログラミング言語同様、ファイルとして実行することもできます。
主に` ファイル名.sh `という拡張子です。

- 使用シェルの指定
` #!/bin/bash `などと書くやつです。使うシステムのシェルに合わせたり使いたいシェルを1行目で指定します。

- 引数をつかう
` $数字 `で引数を使います。$0はコマンドラインの先頭なので自分でつくったりするなら$1から指定します。いくらでも引数は設定できますが、10個目以降は$10でなく${10}と書く必要があります。

- 制御構文:if
```bash:制御構文
if [条件文]
then
  処理
else
  処理
fi
```
条件文にはいろいろ指定できますが、

ファイルに関する条件：
-d 名前 : ディレクトリであるかどうか
-e 名前 : 存在するかどうか

数値に関する条件：
x -eq y : x,yが等しいか
x -ne y : x,yが等しくないか
x -lt y : x < yを満たすか
x -le y : x <= yを満たすか

などがあります。

case文もあり
```bash:case文
case 値 in
パターン1 )
  実行文
;;
パターンn )
  実行文;;
*) # 例外処理
  実行文
;;
esac

# 実際
case $1 in
1 )
  echo '引数1は1ですね'
;;
2 )
  echo '引数1は2ですね';;
*)
  echo '引数1は1と2以外ですね'
;;
esac
```

- for,while
繰り返し構文です
```bash:for,while
for 変数 in リスト
do
  実行文
done

# while文
while 条件文
do
  実行文
done
```

## この記事は以上
UNIXの基礎的なものやコマンドはざっと洗えたと思ってます。
コマンドはまだまだあり全部覚える必要もないと思いますが、一目通しておくと「こんなんあった」が出てくるのでもっと知見を広げたいですね


### 参考文献
SB Creative出版 阿部ひろき 著「入門講座UNIX」
ベル研究所 - wikipedia
qiitaサイト等