山浦清透さん監督のアプレンティスシップの課題に挑戦してみた

## はじめに
インフラエンジニアですが、アプリケーションの動きを学んでみたく、以下のアプレンティスシップの課題の一部に挑戦してみることにしました。

https://apprentice.jp/

コードブロックの中でパブリックIPアドレスの記載がありますが、そちらはすでに使用していないものとなります。


## 課題一覧

ゴールから逆算して学ぶことができる
[linux][Level1] Linux が何かを説明できる
[linux][Level1] Linux の環境を用意することができる
[linux][Level1] ディレクトリを操作できる
[linux][Level1] マニュアルを確認できる
[linux][Level1] ファイルを操作できる
[linux][Level2] 標準入出力を扱える
[linux][Level2] パーミッションを操作できる
[linux][Level3] プロセス・ジョブを管理できる
[linux][Level3] シェルスクリプトを書くことができる

## ゴールから逆算して学ぶことができる

本項目では、以下のリンクに従って、学習計画を立てていきます。

https://github.com/APPRENTICE-jp/apprentice-challenge/blob/main/skilldoc/GOAL.md

ガントチャートを使用したかったので、Notionにまとめることにしました。

https://grave-wasp-f94.notion.site/b9f0d6e887b34b0a9d3b6095e801f342?pvs=4

## Linux が何かを説明できる
本項目のゴールは以下の5つとなります。
- OS とは何かを、プログラミング初心者にわかるように説明する。
- Linux とは何かを、プログラミング初心者にわかるように説明する。
- Linux におけるカーネルとディストリビューションについて、それぞれプログラミング初心者にわかるように説明する
- 有名なディストリビューションを3つ以上挙げる
- シェルとは何か、プログラミング初心者にわかるように説明する。また代表的なシェルを2つ以上挙げる。

#### OS とは何かを、プログラミング初心者にわかるように説明する

「OS」は「オペレーティングシステム」の略です。オペレーティングシステムは、コンピュータが動作するための基本的なソフトウェアです。身近なものに例えるなら、OSはコンピュータの「指揮者」のような存在です。コンピュータ内の様々な部品やプログラムがうまく連携して動作できるように、OSが中心となってコントロールします。

普段皆さんが何気なくしているパソコンの操作も、**実はOSと対話している**ことになり,この"マウスなどを使用してOSと対話する方法"をGUIと呼びます。

詳細は以下を見てみてください。

https://it-trend.jp/words/gui

実はOSと対話する方法はもう一つあります。
仮にWindowsのPCを使用しているなら「Windowsボタン」をおして「cmd」と入力してみてください。
これは「コマンドプロンプト」と呼ばれ、"テキストを使用してOSと対話する"ことが出来るアプリケーションです。
このように"テキストを使用してOSと対話する方法"を「GUI」とは対称的に「CLI」と呼びます。

詳細は以下を見てみてください。

https://e-words.jp/w/CLI.html

主なOSは
- Widwos
- Mac
- Linux

などがあり、Linuxについては次項で説明します。


#### Linux とは何かを、プログラミング初心者にわかるように説明する。
次は、代表的なOSの一つであるLinuxについて説明していきます。

Linux（リナックス）は、コンピュータの基本的な制御を行うソフトウェアで、「オペレーティングシステム（OS）」の一つです。
WindowsやMacなどは皆さんが実際に使用する端末にインストールされていますが、Linuxはサーバにインストールされていることがほとんどかと思います。
WindowsやMac OSと異なる特徴として、Linuxは「無料で使用できるオープンソース」となります。そのためLinuxをベースとして改良や開発をしやすいのが特徴です。

Linuxのシステムは、大まかに言うと、カーネル、シェル、アプリケーションの三層に分けることができます。

- カーネル (Kernel)
システムの中核となる部分で、ハードウェアと直接通信します。
メモリ管理、プロセス管理、デバイスドライバなど、システムの基本的な機能を提供します。

- シェル (Shell)
ユーザーとカーネルの間の仲介役です。
ユーザーからのコマンドを受け取り、カーネルに命令を出します。
コマンドラインインターフェイス(CLI)にて、カーネルと通信します。

- アプリケーション (Applications)
エンドユーザーが直接使用するソフトウェアプログラムで、主にやグラフィカルユーザインターフェイス(GUI)にて、カーネルと通信します。


#### カーネルとディストリビューションについて、それぞれプログラミング初心者にわかるように説明する。

次はLinuxにおけるカーネルとディストリビューションについて説明していきます。

###### カーネルとは
カーネルとは前項で説明した通りに、OSのシステムの中核となる部分で、アプリケーションやシェルを用いて通信がされます。

一連の動きを整理すると

①ユーザがシェルやアプリケーションを操作する
➁シェルやアプリケーションがカーネルと通信をする
※厳密にはシステムコールが生成されて、このシステムコールがカーネルに送信されます
③カーネルが必要に応じて、ハードディスクリソースを操作する
④カーネルからのレスポンスがユーザインタフェース（シェルやアプリケーション）に返され、ユーザは結果を見る

このようになります。

##### ディストリビューションとは
ディストリビューションについての説明の前に、Linuxにおける前提を説明します。

Linuxには狭義と広義の意味があります。
**狭義の意味のLinux は、OS全体を指すものではなく、カーネルを指す言葉**となります。しかし、前項で説明したようにLinuxカーネルを利用するためには、様々なソフトウェアが必要です。この**様々なソフトウェア一式を含んだ状態のOSを広義の意味でLinux**と呼びます。

上記のように、カーネルだけではユーザはOSを利用することができず、様々なソフトウェアが必要になります。
**Linuxカーネル＋様々なソフトウェア一式が組み合わさった形で配布されるもの**が、ディストリビューションと呼ばれます。

本項目で説明した内容は、以下の記事に非常に細かくまとまっていますので、参考にしてみてください。

https://lpi.or.jp/lpic_all/linux/intro/intro02.shtml

#### 有名なディストリビューションを3つ以上挙げる
ディストリビューションが何かわかったところで、有名なディストリビューションの例を見ていきましょう。

- CentOS
- Ubuntu
- Debian

上記などがあります。
様々なディストリビューションが存在しますが、すべてLinuxカーネルが使用されています。


####  シェルとは何か、プログラミング初心者にわかるように説明する。また代表的なシェルを2つ以上挙げる

次にシェルについて深堀していきます。概要については前項で説明しましたので、具体的なシェルの動きについて説明していきます。
仮にWindows を使ってる場合は、「コマンドプロンプト」がシェルに該当します。

例えば、コマンドプロンプト上で以下を実行した場合

```
C:\Users\****\OneDrive\Desktop> echo test > example.txt
```

①ユーザがコマンドを入力
➁シェルがコマンドを解釈する
③シェルがシステムコールを生成し、カーネルに送信する
④カーネルがシステムコールを通じて、テキストファイルを作成し、データを書き込む

上記のような手順で最終的にストレージデバイスにテキストファイルが永続的に保存されます。

またシェルの有名どころでは
- Bash
    主にLinuxディストリビューションで使用されます。
- Powershell
    主にWindowsにて使用されます。

などがあります。

## Linux の環境を用意することができる
一旦AWS上でEC2インスタンスを立ててみました。

## ディレクトリを操作することができる
本項目では、よく使用するコマンドをリストアップします。

1. **現在のディレクトリを確認する**
   ```shell
   pwd
   ```
   
2. **ルートディレクトリに移動する**
   ```shell
   cd /
   ```
   
3. **ホームディレクトリに移動する**
   ```shell
   cd ~
   または
   cd $HOME
   または単に
   cd
   ```
   
4. **一つ上のディレクトリに移動する**
   ```shell
   cd ..
   ```
   
5. **ディレクトリの内容を確認する**
   ```shell
   ls
   ```

6. **現在のディレクトリの隠しファイルを含む全てのファイルとディレクトリを表示する**
   ```shell
   ls -la
   ```


7. **現在のディレクトリの隠しファイルを含む全てのファイルとディレクトリを表示する**
   ```shell
   ls -la
   ```

8. 「/etc」ディレクトリの詳細を知りたいときは、以下のように入力します。
   ```shell
   ls -la　/etc
   ```

9. ホームディレクトリに「projects」というディレクトリを作成するときは、以下のように入力します。
   ```
   mkdir projects
   ```
9. 既存のファイルやディレクトリを削除する場合は「rm」コマンドが使用されます。仮にディレクトリの中身ごと削除したい場合は、「-r」オプションを付けることで削除することが出来ます。
   ```shell
   rm -r  projects
   ```

## マニュアルを確認できる
Linuxにおいて、「man」コマンドで特定のコマンドのマニュアルを表示することが出来ます。

例
   ```
   man ls
    NAME
       ls - list directory contents

SYNOPSIS
       ls [OPTION]... [FILE]...

DESCRIPTION
       List information about the FILEs (the current directory by default).  Sort entries alphabetically if none of -cftuvSUX nor --sort is specified.

       Mandatory arguments to long options are mandatory for short options too.

       -a, --all
              do not ignore entries starting with .

       -A, --almost-all
              do not list implied . and ..

       --author
              with -l, print the author of each file

       以下省略
   ```

実行例
   ```
   man ls
   ```

## 標準入力を扱える
本項目のゴールは以下7つとなります。
- 標準入力、標準出力、標準エラー出力について、プログラミング初心者にわかるように説明する
- リダイレクトを使用して、ルートディレクトリを ls コマンドで出力した結果を、~/root.txt という新規ファイルに保存する
- ルートディレクトリと存在しないファイルを ls コマンドで一度で参照しようとして( ls / /hoge )、その両方の結果を一度に ~/result.txt という新規ファイルに保存する
- /dev/null とは何で、どういう時に使われるものかをプログラミング初心者にわかるように説明する
- ルートディレクトリを ls コマンドで参照した結果を、/dev/null にリダイレクトし、何も表示されないことを確認する
- ルートディレクトリを ls コマンドで参照した結果のうち、"l" から始まるものだけを、パイプラインを使用して一回のコマンドで表示する

#### 標準入力、標準出力、標準エラー出力について、プログラミング初心者にわかるように説明する
説明にあたって、まず前提となるリダイレクトという概念について触れさせて下さい。

リダイレクト（Redirection）は、Linuxやその他のUNIX系オペレーティングシステムで使用される概念で、コマンドの出力や入力を別の場所に向けることができます。**リダイレクトを使うことで、ファイルへの出力、ファイルからの入力、あるいは他のコマンドへの入力/出力などが可能**になります。

本項目での標準入力・標準出力・標準エラー出力はこの「リダイレクト」という概念とセットで使用されることが多いです。

では、それぞれの言葉の意味を説明していきます。

- **標準入力 (stdin)**
標準入力は、プログラムに値を渡す入力元のことです。例えば、コマンドラインでコマンドを実行した際に、キーボードから入力を受け付けることができます。

例
```r
sort < input.txt
apple
banana
cherry
```

この例では**標準入力を「input.txt」にリダイレクト**を実施しています。
つまり、本来画面から入力した値に対してsortコマンドを実行するところを、「input.txt」に対してsortコマンドを実行していることになります。
テキストファイルの中身が以下のようであった場合は、その中身に対してsortコマンドが実行されたわけです。

```r
banana
apple
cherry
```


- **標準出力 (stdout)**
標準出力は、通常、プログラムの主要な出力先です。例えば、コマンドラインでコマンドを実行した際に、その結果が画面に表示されます。

例
```r
echo "Hello, World!" > output.txt
```
上記では、本来画面上に表示される「Hello World!」というテキストが、「output.txt」の中にリダイレクトされる。という動きになります。

- **標準エラー出力 (stderr)**
こちらも出力の一形態ですが、こちらはエラーメッセージを出力するためのものです。これにより、正常な出力とエラーメッセージを区別することができます。

例
```r
cat nonexistentfile.txt
cat: nonexistentfile.txt: No such file or directory
```

上記では、意図的にエラーメッセージを出力させています。通常標準エラー出力は標準出力と同じように画面上に表示されます。

```r
nonexistentfile.txt 2> errorlog.txt
```
上記では本来画面上に表示されるエラー出力を、「errorlog.txt」というテキストファイルにリダイレクトしています。なお標準エラー出力をリダイレクトする場合は「2」が使用されます。

#### リダイレクトを使用して、ルートディレクトリを ls コマンドで出力した結果を、~/root.txt という新規ファイルに保存する

ではいろいろ実践していきましょう。

```r
[ec2-user@ip-172-31-2-123 /]$ sudo su
[root@ip-172-31-2-123 /]# 
#標準出力先をroot.txtにリダイレクトする
[root@ip-172-31-2-123 /]# ls > root.txt
[root@ip-172-31-2-123 /]# ls
bin  boot  dev  etc  home  lib  lib64  local  media  mnt  opt  proc  root  root.txt  run  sbin  srv  sys  tmp  usr  var
[root@ip-172-31-2-123 /]# cat root.txt 
bin
boot
dev
etc
home
lib
lib64
local
media
mnt
opt
proc
root
root.txt
run
sbin
srv
sys
tmp
usr
var
[root@ip-172-31-2-123 /]# 
```
catコマンドで中身を確認すると、しっかり出力結果がリダイレクトされていますね。

#### ルートディレクトリと存在しないファイルを ls コマンドで一度で参照しようとして( ls / /hoge )、その両方の結果を一度に ~/result.txt という新規ファイルに保存する

```r
[root@ip-172-31-2-123 /]# ls /hoge 2> result.txt
[root@ip-172-31-2-123 /]# cat result.txt 
ls: cannot access '/hoge': No such file or directory
[root@ip-172-31-2-123 /]# 
```
ちなみに、「2」と「>」の間にスペースがあると、「2」がlsコマンドのオプションとして解釈されてしまうので注意が必要です。

#### /dev/null とは何で、どういう時に使われるものかをプログラミング初心者にわかるように説明する

 /dev/null は特別なファイルで実質ゴミ箱です。書き込まれたデータをすべて捨てる役割を果たします。
例

```r
command > /dev/null 2>&1
```

上記のコマンドでは、コマンドの出力結果もエラー出力もすべて/dev/nullにリダイレクトされ、結果的に何も表示されません。

使用用途としては
- ログの消去
- 不要な出力の削除

などが挙げられます。

#### ルートディレクトリを ls コマンドで参照した結果を、/dev/null にリダイレクトし、何も表示されないことを確認する

```r
[root@ip-172-31-2-123 /]# ls
bin  boot  dev  etc  home  lib  lib64  local  media  mnt  opt  proc  result.txt  root  root.txt  run  sbin  srv  sys  tmp  usr  var
[root@ip-172-31-2-123 /]# ls > dev/null
[root@ip-172-31-2-123 /]# 
```
上記では、本来lsコマンドの出力結果は画面に表示されますが、dev/nullファイルにリダイレクトしています。

#### ルートディレクトリを ls コマンドで参照した結果のうち、"l" から始まるものだけを、パイプラインを使用して一回のコマンドで表示する

```r
[root@ip-172-31-2-123 /]# ls | grep '^l'
lib
lib64
local
[root@ip-172-31-2-123 /]# 
```
「|」はコマンドの実行結果を右に渡す。という意味です。
そのため、lsコマンドの実行結果をgrepコマンドでソートをかける。ということを上記でしています。

## パーミッションを操作できる
本項目のゴールは以下5つとなります。

- ホームディレクトリにREADEME.mdというファイルを作成し、ファイルのオーナーとグループを確認する
- READEME.mdファイルのパーミッションを確認し、誰に何の権限が付与されているのか説明する
- README.md ファイルのオーナーに対して、読み取り、書き込み、実行の全ての権限を付与する
- ホームディレクトリの直下に、permission という名前の空ディレクトリを作成し、permission ディレクトリのグループに対して、書き込み権限を付与する
- スーパーユーザーとして、ホームディレクトリの直下に superuser という名前の空ディレクトリを作成する
作成後、superuser ディレクトリのオーナーが誰かを確認する

#### ホームディレクトリにREADEME.mdというファイルを作成し、ファイルのオーナーとグループを確認する

```r
[ec2-user@ip-172-31-2-123 ~]$ touch REDME.md
[ec2-user@ip-172-31-2-123 ~]$ ls
REDME.md  project
[ec2-user@ip-172-31-2-123 ~]$ ls -l REDME.md 
-rw-r--r--. 1 ec2-user ec2-user 0 Oct  1 07:31 REDME.md
```
lsコマンドの-lオプションでそのファイルやディレクトリの詳細を確認することが出来ます。
「READEME.md」ファイルの場合オーナーとグループがともに「ec2-user」であることがわかります。

#### READEME.mdファイルのパーミッションを確認し、誰に何の権限が付与されているのか説明する
先ほどのlsコマンドの実行結果で、「-rw-r--r--」に着目すると、ファイルのパーミッションについても読み取ることが出来ます。

- 第1文字: ファイルタイプ
"-"は通常のファイルを表します。
d はディレクトリを表します。
l はシンボリックリンクを表します。
今回は - なので、通常のファイルを表しています。

- 第2文字から第4文字: ユーザー（オーナー）の権限
rw- は、オーナーに対して読み取り (r) と書き込み (w) の権限があり、実行 (x) の権限はないことを示します。

- 第5文字から第7文字: グループの権限
r-- は、グループメンバーに対して読み取り (r) の権限のみがあり、書き込み (w) や実行 (x) の権限はないことを示します。

- 第8文字から第10文字: その他のユーザーの権限
r-- は、その他のユーザーに対して読み取り (r) の権限のみがあり、書き込み (w) や実行 (x) の権限はないことを示します。

#### README.md ファイルのオーナーに対して、読み取り、書き込み、実行の全ての権限を付与する

```r
[ec2-user@ip-172-31-2-123 ~]$ chmod 744 REDME.md 
[ec2-user@ip-172-31-2-123 ~]$ ls -l
total 0
-rwxr--r--. 1 ec2-user ec2-user 0 Oct  1 07:31 REDME.md
```
権限の変更はchmodコマンドにて実行可能です。

#### ホームディレクトリの直下に、permission という名前の空ディレクトリを作成し、permission ディレクトリのグループに対して、書き込み権限を付与する

```r
[ec2-user@ip-172-31-2-123 ~]$ chmod 722 permission/
[ec2-user@ip-172-31-2-123 ~]$ ls -l
total 0
-rwxr--r--. 1 ec2-user ec2-user 0 Oct  1 07:31 REDME.md
drwx-w--w-. 2 ec2-user ec2-user 6 Oct  1 08:02 permission
drwxr-xr-x. 2 ec2-user ec2-user 6 Sep 30 12:18 project
```
上記のようにディレクトリのグループに対しての権限変更では、3つの数字のうち真ん中の数字を「2」とすることで、ディレクトリに書き込み権限を付与することが出来ます。

#### スーパーユーザーとして、ホームディレクトリの直下に superuser という名前の空ディレクトリを作成する。作成後、superuser ディレクトリのオーナーが誰かを確認する

```r
[ec2-user@ip-172-31-2-123 ~]$ sudo su
[root@ip-172-31-2-123 ec2-user]# cd ~
[root@ip-172-31-2-123 ~]# mkdir superuser
[root@ip-172-31-2-123 ~]# ls -l
total 0
drwxr-xr-x. 2 root root 6 Oct  1 08:08 superuser
```
スーパーユーザーで作成したディレクトリやファイルは、オーナーが「root」になります。

## プロセスジョブを管理できる
本項目のゴールは以下の2つとなります。
- 全ユーザーのプロセスを表示する
- sleepコマンドを利用して処理を100秒停止させる処理を、バックグラウンドで実行する

#### 全ユーザーのプロセスを表示する

プロセスの確認は、psコマンドで実施できます。
今回は「aux」オプションを付けており、以下のような意味になります。

a：ターミナルに接続している全てのユーザーのプロセスを表示する
u：ユーザー指向の形式で出力を表示する
x：ターミナルに接続していないプロセスも表示する。
※インタフェースから直接起動されないプロセス

```r
[ec2-user@ip-172-31-2-123 ~]$ ps aux
USER         PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
root           1  0.0  1.6 170696 16316 ?        Ss   Sep30   0:11 /usr/lib/systemd/systemd --switched-root --system --deserialize=32
root           2  0.0  0.0      0     0 ?        S    Sep30   0:00 [kthreadd]
root           3  0.0  0.0      0     0 ?        I<   Sep30   0:00 [rcu_gp]
root           4  0.0  0.0      0     0 ?        I<   Sep30   0:00 [rcu_par_gp]
root           5  0.0  0.0      0     0 ?        I<   Sep30   0:00 [slub_flushwq]
root           6  0.0  0.0      0     0 ?        I<   Sep30   0:00 [netns]
root           8  0.0  0.0      0     0 ?        I<   Sep30   0:00 [kworker/0:0H-events_highpri]
# 省略
```

#### sleepコマンドを利用して処理を100秒停止させる処理を、バックグラウンドで実行する

そもそもsleepコマンドとは、シェルスクリプトの実行を一定時間停止させるコマンドです。
例えば、スクリプトが何か処理を行い、次の処理が実施されるまでに一定時間待つ必要がある場合に使用されます。

```r
[ec2-user@ip-172-31-2-123 ~]$ sleep 100 &
[1] 85656
[ec2-user@ip-172-31-2-123 ~]$ kill 85656
```
上記コマンドでは、バックグラウンドでsleepコマンド実行し、その後そのプロセスを停止させています。

## シェルスクリプトを書くことができる。
本項目のゴールは以下となります。
- シェルスクリプトのファイルを作成し、「Hello!」と出力する
- シェルスクリプトのファイルに「What's your name?」と出力し、ユーザーに名前の入力を求めます。その後ユーザーが入力した名前に対して、「Welcome, $name!」（$name は入力された名前）と出力する処理を追加する
- 四則演算を行う電卓を作成する
```r
Enter two numbers:
10 # ユーザーが入力
11 # ユーザーが入力
Choose an arithmetic operation (+, -, *, /):
+ # ユーザーが入力
The result:21
```
- for 文 または while 文を利用して、1~100までのうち、偶数の数字を表示する処理を作成する
```r
2 4 8 ... 100
```

####  シェルスクリプトのファイルを作成し、「Hello!」と出力する

シェルスクリプト作成にあたって、viエディターを使用することにしました。

```r
[ec2-user@ip-172-31-2-123 ~]$ vi hello.sh
[ec2-user@ip-172-31-2-123 ~]$ ls -l
total 4
-rw-r--r--. 1 ec2-user ec2-user 14 Oct  2 11:16 hello.sh
[ec2-user@ip-172-31-2-123 ~]$ chmod 722 hello.sh 
[ec2-user@ip-172-31-2-123 ~]$ ls -l
total 4
-rwx-w--w-. 1 ec2-user ec2-user 14 Oct  2 11:16 hello.sh
[ec2-user@ip-172-31-2-123 ~]$ ./hello.sh 
Hello!
```

なお、作成したスクリプトファイルは以下のようになります。
```r
[ec2-user@ip-172-31-2-123 ~]$ cat hello.sh 
echo "Hello!"
```

#### シェルスクリプトのファイルに「What's your name?」と出力し、ユーザーに名前の入力を求める。その後ユーザーが入力した名前に対して、「Welcome, $name!」（$name は入力された名前）と出力する処理を追加する

今回はreadコマンドを使用します。
read コマンドは、シェルスクリプト内でユーザーからの入力を受け取るためのコマンドです。変数名を指定することで、ユーザーからの入力をその変数に格納することができます。

```r
[ec2-user@ip-172-31-2-123 ~]$ vi greet.sh
[ec2-user@ip-172-31-2-123 ~]$ 
[ec2-user@ip-172-31-2-123 ~]$ chmod +x greet.sh 
[ec2-user@ip-172-31-2-123 ~]$ 
[ec2-user@ip-172-31-2-123 ~]$ sh greet.sh 
What's your name?
Keiichi
Welcome, Keiichi!
[ec2-user@ip-172-31-2-123 ~]$ 
[ec2-user@ip-172-31-2-123 ~]$ cat greet.sh 
echo "What's your name?"
read name
echo "Welcome, $name!"
[ec2-user@ip-172-31-2-123 ~]$ 

```

#### 四則演算を行う電卓を作成する
割り算の時の割る数が 0 であるケースや、演算子の記号 +, -, *, / が合致しない場合は、エラー出力をするようにしました。

```r
#!/bin/bash

# 数値の入力を求める
echo "Enter two numbers:"
read num1
read num2

# 演算子の入力を求める
echo "Choose an arithmetic operation (+, -, *, /):"
read operator

# 入力された演算子に基づいて計算を行い、結果を表示する
case $operator in
  +)
    result=$(echo "$num1 + $num2" | bc)
    ;;
  -)
    result=$(echo "$num1 - $num2" | bc)
    ;;
  \*)
    result=$(echo "$num1 * $num2" | bc)
    ;;
  /)
    if [ $num2 -eq 0 ]; then
      echo "Cannot divide by zero."
      exit 1
    fi
    result=$(echo "scale=2; $num1 / $num2" | bc)
    ;;
  *)
    echo "Invalid operator."
    exit 1
    ;;
esac

echo "The result: $result"
```
シェルスクリプトは普段書かないので、インプットの一環として丁寧に解説していきます。
以下のスクリプトでは以下を実施しています。

- 変数「num1」と「num2」に対して、それぞれのユーザーインプットを確認する
- 変数「operator」に、(+, -, *, /)の中でユーザーが選んだものを格納する

```r
#!/bin/bash

# 数値の入力を求める
echo "Enter two numbers:"
read num1
read num2

# 演算子の入力を求める
echo "Choose an arithmetic operation (+, -, *, /):"
read operator
```

次に、こちらのスクリプトで以下を実施しています。
詳細は後述します。
- 「case文」を用いて、「operator」に格納された変数に基づいて分類わけする
- ユーザーインプットに応じて、それぞれの処理を実行する

```r
case $operator in
  +)
    result=$(echo "$num1 + $num2" | bc)
    ;;
  -)
    result=$(echo "$num1 - $num2" | bc)
    ;;
  \*)
    result=$(echo "$num1 * $num2" | bc)
    ;;
  /)
    if [ $num2 -eq 0 ]; then
      echo "Cannot divide by zero."
      exit 1
    fi
    result=$(echo "scale=2; $num1 / $num2" | bc)
    ;;
  *)
    echo "Invalid operator."
    exit 1
    ;;
esac
```
まず「case文」ですが、これは複数のパターンに基づいてコマンドを実行する際に用いられます。
例

```r
# case 評価される値 in ではじまる
case expression in
# 「)」でそれぞれのパターンが記載され、「;;」で区切られる
    pattern1)
        commands1;;
    pattern2)
        commands2;;
    pattern3)
        commands3;;
# パターンの例外は「*)」以下に実施するコマンドを記載する
    *)
        default_commands;;
# 「esac」で「case文」が終了する
esac
```
では処理の中身についてみていきます。
ここでは、他と比べて複雑な「/」「＊」以下の処理について深堀します。

まずは細かくスクリプトを見る前に、if文について確認します。
「if文」は条件分岐の基本的な構造で、以下のように使用することが出来ます。

例
```r
# 条件は「[ 条件 ]; then」で記載
if [ condition1 ]; then
    # commands
# 別の条件を追加する場合は「elif」で条件を追加する
elif [ condition2 ]; then
    # commands
# 指定した条件に当てはまらない場合は、「else」で条件を追加する
else
    # commands
# 「if」文の終わりに「fi」を追加する
fi
```
では実際のスクリプトを確認します。

```r
  /)
# 「operatar」が「/」かつ「num2」が0だった場合の条件分岐
    if [ $num2 -eq 0 ]; then
      echo "Cannot divide by zero."
# 「exit 1」はコマンドの終了を意味し、Linux系システムでは0以外は「失敗」を意味します。
      exit 1
    fi
# 「scale=2;」は小数点以下2桁をbcコマンドに渡す意味を持ちます
    result=$(echo "scale=2; $num1 / $num2" | bc)
    ;;
  *)
    echo "Invalid operator."
    exit 1
    ;;
```
これで、0で「num1」を割ろうとした場合と、「operator」に無効化な値が格納された場合にエラーを出すような仕組みを作成することができました。

本スクリプトも残りは以下のみとなります。
「esac」はcase文の終わりを示しています。
そのため
・case文の終わりを示す
・計算結果を表示する

上記がこちらのスクリプトで実施している内容となります。

```r
esac

echo "The result: $result"
```

#### for 文 または while 文を利用して、1~100までのうち、偶数の数字を表示する処理を作成する

では早速スクリプトを作成していきます。
今回はfor文を使用しますので、その解説から始めます。

for文は、特定の条件が満たされるまでコードブロックを繰り返し実行する制御構造です。


```r
# 「i」という変数が「range」で指定した範囲の中で、「commands」が実行される
for i in {range}
do
  commands
done
```

例えば、1から10までの数字を表示する場合は以下のようなスクリプトになります。

```r
#!/bin/bash
# 1から10までの数字を表示する
for i in {1..10}
do
  echo "Number $i"
done
```

ではそれらを踏まえて課題となるスクリプトを作成していきましょう。

```r
#!/bin/bash

# 1から100までループ
for i in {1..100}
do
  # 数値が偶数であるかどうかを確認
　# Bash では、算術評価は $(( ... )) という構文を使用して行われる
  if [ $(($i % 2)) -eq 0 ]; then
    echo $i
  fi
done
```
上記のようなスクリプトを実行すると、以下のような結果が出力されます。

```r
[ec2-user@ip-172-31-2-123 ~]$ sh evennumber.sh 
2
4
6
8
~省略~
98
100
```
以上でLinuxパートを終了します。

## おわりに
今回はLinuxパートのみでしたが、Gitについても課題も存在します。
一旦切りが良いので、ここまでの内容とさせてもらいます。