Linuxの基礎 5日目

# 5日目

## 1 シェル

### 1-1 シェルの役割と基本を知ろう
- シェルはコマンドを実行するインタープリタである
  ```
  # シェルを確認する際にはpsコマンドを使用する
  $ ps
   PID TTY          TIME CMD
    15 pts/1    00:00:00 bash
    69 pts/1    00:00:00 su
    86 pts/1    00:00:00 su
    87 pts/1    00:00:00 bash
   119 pts/1    00:00:00 ps
  ```
  - シェルの種類
    | シェル | 説明 |
    | ---- | ---- |
    | sh(Bourne Shell) | UNIXの標準シェル。機能がシンプル |
    | bash(Bourne Again Shell) | shを拡張して多機能にしたシェル。macOSでも標準 |
    | csh(C shell) | C言語に似たスクリプトを使えるシェル |
    | tcsh | cshを拡張したシェル |
    | ksh(Korn shell) | shを拡張したシェル |
    | zsh | kshにbashやtcshの機能を取り込んだ多機能シェル |
- シェルはコマンド実行時にいくつかのメタキャラクタを展開する
- 標準出力をリダイレクトするとコマンドの出力をファイルで保存できる
  - 標準入出力
    - Linux上で実行されるプログラムには、デフォルトで3つの出入り口が用意されている。以下に3つの出入り口を記載する
      - 標準入力
        - キーボード(入力装置)から入力(コマンド)を受け付ける
      - 標準出力
        - 入力装置で受け取ったプログラム結果を受け付け出力する
      - 標準エラー出力
        - 入力装置で受け取ったプログラムのエラー結果を受け付け出力する
  - リダイレクト(**>**)
    - コマンドの標準出力を端末画面ではなく、任意のファイルに切り替えることが可能(出力結果をファイルに出力する)
      ```
      # リダイレクトの例
      # 以下のコマンドは、日付(date)コマンドの出力を、today.txtに切り替えファイル内に記載する
      $ date > today.txt

      # today.txtファイルの内容
      $ cat today.txt
      Tue Aug  8 08:38:03 AM JST 2023

      # もう一度リダイレクト(もう一度リダイレクトすると、内容が上書きされる)
      $ date > today.txt
      $ cat today.txt
      Tue Aug  8 08:40:00 AM JST 2023

      # 追記リダイレクト
      # 上書きではなく、ファイルの末尾に追記する場合は、「>」の代わりに「>>」を使用する
      $ date >> today
      Tue Aug  8 08:40:00 AM JST 2023
      Tue Aug  8 08:46:53 AM JST 2023

      # 標準エラー出力のリダイレクトの例
      $ ls -l today.txt nofile 2> stderr.txt

      $ cat stderr.txt
      ls: cannot access 'nofile': No such file or directory
      ```
- パイプ(**|**)を使うと他のコマンドの出力を別のコマンドで処理できる
  - パイプは1画面に収まりきらない出力をlessコマンドで表示するときなどによく使用する
    ```
    # historyコマンドの実行結果をlessで表示
    $ history | less
      1  pwd
      2  su - general0917
      3  su -
      4  id
      5  pwd
      6  su
      7  pwd
      8  passwd
      9  sudo -i
      10  su
      11  pwd
      12  ifconfig
      13  ruby -v
      14  exit
      15  ls
      16  date > today.txt
      17  cd LPICの基礎/
      18  cd practice_linux/
    ```
- シェルにとって特別な意味を持つ文字をメタキャラクタという  
  - ファイル名の指定などに利用できる主なメタキャラクタは以下の表のとおり
    | シェル | 説明 |
    | ---- | ---- |
    | * | 0文字以上の任意の文字列 |
    | ? | 任意の1文字 |
    | [] | []内の任意の1文字 |
    | \ | メタキャラクタの打ち消し |
    ```
    # ファイルの一覧を表示
    $ cd LPICの基礎/practice_linux
    $ ls
    1.txt  2.txt  3.txt  4.txt  5.txt  a1.txt  a2.txt  a3.txt  ab.txt  b1.txt  b2.txt  c1.txt  c3.txt  sample_new.txt  sample.txt  stderr.txt  today.txt

    # 「*」と「?」の違い

    # .txtの前が0文字以上のファイルを表示する
    $ ls *.txt 
    1.txt  2.txt  3.txt  4.txt  5.txt  a1.txt  a2.txt  a3.txt  ab.txt  b1.txt  b2.txt  c1.txt  c3.txt  sample_new.txt  sample.txt  stderr.txt  today.txt

    # .txtの前が1文字だけのファイルを表示する
    $ ls ?.txt
    1.txt  2.txt  3.txt  4.txt  5.txt

    # []を使うと、[]内の1文字とマッチする。
    # []を使った場合の例(「a」もしくは「b」で始まる名前のファイルにマッチする)
    $ ls [ab]*.txt
    1.txt  a2.txt  a3.txt  ab.txt  b1.txt  b2.txt

    # []内は「-」を使って範囲を指定することも可能
    # 範囲の指定
    $ ls [3-5].txt
    3.txt  4.txt  5.txt

    # 次の例では、ファイル名に「1」か「3」が含まれるファイルにマッチする
    # ファイル名に「1」か「3」が含まれるファイル
    $ ls *[13]*
    1.txt  3.txt  a1.txt  a3.txt  b1.txt  c1.txt  c3.txt
    ```

### 1-2 シェルの便利な機能
- コマンド履歴を利用することができる
  - コマンドライン上で、**↑**キーを押下することで、以前実行したコマンド履歴が順にさかのぼって表示される
  - **history**コマンドを実行すると、コマンド履歴の一覧を表示することができる
    ```
    # history
      1  pwd
      2  su - general0917
      3  su -
      4  id
      5  pwd
      6  su
      7  pwd
      8  passwd
      9  sudo -i
      10  su
      11  pwd
      12  ifconfig
      13  ruby -v
      14  exit
      15  ls
      16  date > today.txt
      17  cd LPICの基礎/
      18  cd practice_linux/
      19  date > today.txt
      20  cat today.txt
      21  date > today.txt
      22  cat today.txt
      23  date >> today.txt
      24  cat today.txt
      25  su
      26  pwd
      27  id
      28  cd LPICの基礎/
      29  cd practice_linux/
      30  ls -l today.txt nofile 2 > stderr.txt
      31  ls -l today.txt nofile 2> stderr.txt
      32  history | less
      33  cd LPICの基礎/
      34  cd practice_linux/
      35  pwd
      36  ls
      37  ls *.txt
      38  ls ?.txt
      39  vi 1.txt
      40  vi 2.txt
      41  ls ?.txt
      42  ls *.txt
      43  vi ab.txt
      44  vi a1.txt
      45  vi a2.txt
      46  vi b1.txt
      47  vi b2.txt
      48  vi 3.txt
      49  vi 4.txt
      50  vi 5.txt
      51  vi c3.txt
      52  vi a3
      53  vi c1.txt
      54  ls
      55  ls *.txt
      56  ls
      57  ls ?.txt
      58  ls [ab]*.txt
      59  ls [3-5].txt
      60  vi 1
      61  ls *[13]*
      62  cd LPICの
      63  cd LPICの基礎/
      64  cd practice_linux/
      65  wsl -l -v
      66  history
      67  pwd
      68  ps
      69  history

    # 数字は履歴番号であり、「!履歴番号」を実行すると、指定した履歴番号のコマンドが再度実行される
    $ !68
    PID TTY          TIME CMD
     88 pts/0    00:00:00 bash
    113 pts/0    00:00:00 ps
    ```
- **Tab**キーを押すとコマンドやファイル名の補完ができる
  - コマンドやファイル名、ディレクトリ名、パス名など入力するさいは、**Tab**キーを押下すると、補完が可能
    ```
    # コマンド補完の例
    $ his # この状態でTabキーを押下すると正しく、補完される
    $ history

    # ファイル名補完の例
    $ cd LPICの基礎/practice_linux/data
    $ cat p # この状態でTabキーを押下すると候補が表示される
    ps.txt   pwd.txt

    $ cat pw # この状態でTabキーを押下すると残りの部分が補完される
    $ cat pwd.txt
    ```
- コマンド名に別名(エイリアス)を付けることができる
  - エイリアスを使うことによって、次のようなことができる
    - よく使うコマンドに短縮名を付ける
    - コマンドとオプションをまとめて1つのコマンドのように使う
    - 連続したコマンド処理を簡単に実行する
  - エイリアスの設定は**alias**コマンドを使用する
    ```
    # エイリアスのコマンド書式
    alias [別名[=コマンド]]

    # エイリアスlaの設定
    $ alias la='ls -la'

    # エイリアスlaの実行
    $ la
    drwx------ 2 general0917 general0917  4096 Aug  8 12:39 .
    drwxr-xr-x 3 root        root         4096 Aug  8 06:30 ..
    -rw------- 1 general0917 general0917   894 Aug  9 02:23 .bash_history
    -rw-r--r-- 1 general0917 general0917    18 Nov 24  2022 .bash_logout
    -rw-r--r-- 1 general0917 general0917   141 Nov 24  2022 .bash_profile
    -rw-r--r-- 1 general0917 general0917   492 Nov 24  2022 .bashrc
    -rw------- 1 general0917 general0917    20 Aug  8 12:20 .lesshst
    -rw------- 1 general0917 general0917 27039 Aug  8 12:39 .viminfo

    # エイリアスlslの設定
    $ alias lsl='ls -l | less'

    # エイリアスlslの設定
    $ lsl /etc
    drwxr-xr-x 91 root root     4096 Aug  9 03:42 ./
    dr-xr-xr-x 19 root root     4096 Aug  8 20:41 ../
    -rw-r--r--  1 root root       16 Jun 26 19:40 adjtime
    -rw-r--r--  1 root root     1529 Jun 23  2020 aliases
    drwxr-xr-x  2 root root     4096 Aug  8 06:40 alternatives/
    -rw-r--r--  1 root root      541 Jul 11  2022 anacrontab
    drwxr-x---  4 root root     4096 Aug  8 06:37 audit/
    drwxr-xr-x  3 root root     4096 Aug  8 06:37 authselect/
    drwxr-xr-x  2 root root     4096 Aug  8 06:38 bash_completion.d/
    -rw-r--r--  1 root root     2658 Dec 21  2022 bashrc
    -rw-r--r--  1 root root      535 Jun  6 21:45 bindresvport.blacklist
    drwxr-xr-x  2 root root     4096 Jul 17 17:37 binfmt.d/
    -rw-r--r--  1 root root       24 Apr  6 22:27 centos-release
    -rw-r--r--  1 root root     1371 Aug 29  2022 chrony.conf
    -rw-r-----  1 root chrony    540 Aug 29  2022 chrony.keys
    drwxr-xr-x  2 root root     4096 Jul 11 01:31 cifs-utils/
    drwxr-xr-x  5 root root     4096 Aug  8 06:37 cloud/
    drwxr-xr-x  4 root root     4096 Jul 27 00:37 cockpit/
    drwxr-xr-x  2 root root     4096 Jun 26 19:37 cron.d/
    drwxr-xr-x  2 root root     4096 Aug 10  2021 cron.daily/
    -rw-r--r--  1 root root        0 Jul 11  2022 cron.deny
    drwxr-xr-x  2 root root     4096 Aug 10  2021 cron.hourly/
    drwxr-xr-x  2 root root     4096 Aug 10  2021 cron.monthly/
    -rw-r--r--  1 root root      451 Aug 10  2021 crontab
    drwxr-xr-x  2 root root     4096 Aug 10  2021 cron.weekly/
    drwxr-xr-x  6 root root     4096 Jul 31 23:42 crypto-policies/
    -rw-------  1 root root        0 Jun 26 19:37 crypttab
    -rw-r--r--  1 root root     1401 Dec 21  2022 csh.cshrc
    -rw-r--r--  1 root root     1087 Dec 21  2022 csh.login
    drwxr-xr-x  4 root root     4096 Aug  8 06:37 dbus-1/
    drwxr-xr-x  3 root root     4096 Jun 26 19:40 dconf/
    drwxr-xr-x  2 root root     4096 Aug  8 06:37 debuginfod/
    drwxr-xr-x  2 root root     4096 Aug  8 06:37 default/
    drwxr-xr-x  2 root root     4096 Jun 26 19:37 depmod.d/
    drwxr-x---  4 root root     4096 Jun 26 19:38 dhcp/
    -rw-r--r--  1 root root     4673 Jan  6  2023 DIR_COLORS
    -rw-r--r--  1 root root     4755 Jan  6  2023 DIR_COLORS.lightbgcolor
    (以下省略)

　　# エイリアスの確認コマンド書式
    alias

    # エイリアスの確認
    $ alias
    alias egrep='egrep --color=auto'
    alias fgrep='fgrep --color=auto'
    alias grep='grep --color=auto'
    alias l.='ls -d .* --color=auto'
    alias la='ls -la'
    alias ll='ls -l --color=auto'
    alias ls='ls --color=auto'
    alias lsl='ls -l | less'
    alias xzegrep='xzegrep --color=auto'
    alias xzfgrep='xzfgrep --color=auto'
    alias xzgrep='xzgrep --color=auto'
    alias zegrep='zegrep --color=auto'
    alias zfgrep='zfgrep --color=auto'
    alias zgrep='zgrep --color=auto'

    # エイリアスの削除(解除)コマンド書式
    unalias エイリアス名
    
    # エイリアスの削除
    $ unalias la
    $ unalias lsl

    # エイリアスの確認
    $ alias
    alias egrep='egrep --color=auto'
    alias fgrep='fgrep --color=auto'
    alias grep='grep --color=auto'
    alias l.='ls -d .* --color=auto'
    alias ll='ls -l --color=auto'
    alias ls='ls --color=auto'
    alias xzegrep='xzegrep --color=auto'
    alias xzfgrep='xzfgrep --color=auto'
    alias xzgrep='xzgrep --color=auto'
    alias zegrep='zegrep --color=auto'
    alias zfgrep='zfgrep --color=auto'
    alias zgrep='zgrep --color=auto'

    # 引用符の代わりにエスケープシーケンスを使用
    $ alias ls=ls \-la
    $ alias
    alias egrep='egrep --color=auto'
    alias fgrep='fgrep --color=auto'
    alias grep='grep --color=auto'
    alias l.='ls -d .* --color=auto'
    alias la='ls -la'
    alias ll='ls -l --color=auto'
    alias ls='ls --color=auto'
    alias xzegrep='xzegrep --color=auto'
    alias xzfgrep='xzfgrep --color=auto'
    alias xzgrep='xzgrep --color=auto'
    alias zegrep='zegrep --color=auto'
    alias zfgrep='zfgrep --color=auto'
    alias zgrep='zgrep --color=auto'
    ```
  - 引用符
    - シングルクォーテーション(**'**)
      - 文字列のみとして展開される
    - ダブルクォーテーション(**"**)
      - 変数として展開される
    ```
    # シングルクォーテーションとダブルクォーテーションの違い

    # シングルクォーテーション
    $ name=Penguin
    $ echo 'Hello, $name.'
    Hello, $name.

    # ダブルクォーテーション
    # echo "Hello, $name"
    Hello, Penguin.

    # 違いを見てわかる通り、シングルクォーテーションは文字列のみで展開され、ダブルクォーテーションは変数として展開される
    ```

### 1-3 シェル変数と環境変数
- シェルの動作を規定する変数が用意されている
  | 変数 | 説明 |
  | ---- | ---- |
  | HOME | ユーザーのホームディレクトリ |
  | HOSTNAME | ホスト名(コンピュータ名) |
  | LANG | ユーザーの言語処理方式 |
  | PATH | コマンドを検索するディレクトリリスト |
  | PS1 | プロンプトの表示項目 |
  | PWD | カレントディレクトリのパス |
  | UID | ユーザーID |
  | USER | ユーザー名 |
  - 変数に値を設定することは可能
    ```
    # 変数に値を設定する
    # 「=」の前後にスペースを入れないようにする!!
    変数名=値

    # 変数の設定
    $ var=Linux

    # 変数の内容を表示する書式
    echo $変数名

    # 変数に内容を表示
    $ echo $var
    Linux

    # 変数の有効範囲
    $ var=Linux
    $ echo $var
    Linux

    # このbashコマンドで新しいシェルを起動しているので、新しいシェルではvar変数は参照されない
    $ bash
    echo $var

    # bash(シェル)のログアウトで変数を設定したときのシェルに戻り、参照が可能になる
    $exit
    echo $var
    Linux
    ```
- 変数にはシェル変数と環境変数がある
  - シェル変数
    - 1つのシェルの中だけで使える変数
  - 環境変数
    - 設定したシェルと、そのシェル上で起動したシェルや実行したコマンドでも使える変数
    - 環境変数は**export**コマンドで設定する
    | オプション | 説明 |
    | ---- | ---- |
    | -f | シェル変数を参照する |
    | -n | 指定した環境変数をシェル変数に変える(指定した環境変数を削除する) |
    | -p | 全てのエクスポートされた変数と関数を全て一覧表示する（変数名は指定できない） |
    ```
    # 環境変数の設定コマンド書式
    export [オプション] [変数名[=値]]

    # 環境変数VAR1と環境変数VAR2を設定
    $ VAR1=ubuntu
    $ export VAR1
    $ export VAR2=centos

    # 設定されている環境変数を確認する
    $ export -p
    declare -x DEBUGINFOD_URLS="https://debuginfod.centos.org/ "
    declare -x DISPLAY=":0"
    declare -x HISTCONTROL="ignoredups"
    declare -x HISTSIZE="1000"
    declare -x HOME="/home/general0917/"
    declare -x HOSTNAME="General0917"
    declare -x HOSTTYPE="x86_64"
    declare -x LANG="en_US.UTF-8"
    declare -x LESSOPEN="||/usr/bin/lesspipe.sh %s"
    (以下省略)
    declare -x PULSE_SERVER="unix:/mnt/wslg/PulseServer"
    declare -x PWD="/home/general0917/"
    declare -x SHELL="/bin/bash"
    declare -x SHLVL="1"
    declare -x TERM="xterm-256color"
    declare -x USER="general0917"
    declare -x VAR1="ubuntu"
    declare -x VAR2="centos"
    (以下省略)

    # 環境変数を削除する
    $ export -n VAR1
    $ export -n VAR2


    # 設定されている環境変数を確認する(VAR1, VAR2が削除されている)
    $ export -p
    declare -x DEBUGINFOD_URLS="https://debuginfod.centos.org/ "
    declare -x DISPLAY=":0"
    declare -x HISTCONTROL="ignoredups"
    declare -x HISTSIZE="1000"
    declare -x HOME="/home/general0917/"
    declare -x HOSTNAME="General0917"
    declare -x HOSTTYPE="x86_64"
    declare -x LANG="en_US.UTF-8"
    declare -x LESSOPEN="||/usr/bin/lesspipe.sh %s"
    (以下省略)
    declare -x PULSE_SERVER="unix:/mnt/wslg/PulseServer"
    declare -x PWD="/home/general0917/"
    declare -x SHELL="/bin/bash"
    declare -x SHLVL="1"
    declare -x TERM="xterm-256color"
    declare -x USER="general0917"
    (以下省略)
    ```
  - 設定されている環境変数を表示するには、**printenv**コマンドを実行する
    ```
    # 環境変数を表示
    $ printenv
    SHELL=/bin/bash
    HISTCONTROL=ignoredups
    WSL2_GUI_APPS_ENABLED=1
    WSL_DISTRO_NAME=CentOSStream9
    WT_SESSION=12ef6a84-c632-47fe-b9f7-f22678b13639
    HISTSIZE=1000
    HOSTNAME=General0917
    NAME=General0917
    PWD=/home/general0917/
    LOGNAME=general0917
    HOME=/home/general0917/
    LANG=en_US.UTF-8
    WSL_INTEROP=/run/WSL/256_interop
    (以下省略)
    USER=general0917
    DISPLAY=:0
    SHLVL=1
    XDG_RUNTIME_DIR=/mnt/wslg/runtime-dir
    DEBUGINFOD_URLS=https://debuginfod.centos.org/
    WSLENV=WT_SESSION::WT_PROFILE_ID
    which_declare=declare -f
    PATH=/home/general0917//.local/bin:/home/general0917//bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/usr/lib/wsl/lib
    MAIL=/var/spool/mail/general0917
    HOSTTYPE=x86_64
    PULSE_SERVER=unix:/mnt/wslg/PulseServer
    WT_PROFILE_ID={d42969d1-4eb6-5ae3-aeea-40448e309a3c}
    BASH_FUNC_which%%=() {  ( alias;
    eval ${which_declare} ) | /usr/bin/which --tty-only --read-alias --read-functions --show-tilde --show-dot $@
    }
    _=/usr/bin/printenv
    ```
  - 設定されているシェル変数と環境変数をすべて表示するには**set**コマンドを実行する
    ```
    # シェル変数と環境変数を表示
    $ set
    BASH=/bin/bash
    (以下省略)
    HISTFILE=/home/general0917//.bash_history
    HISTFILESIZE=1000
    HISTSIZE=1000
    HOME=/home/general0917/
    HOSTNAME=General0917
    HOSTTYPE=x86_64
    (以下省略)
    TERM=xterm-256color
    UID=1000
    USER=general0917
    WAYLAND_DISPLAY=wayland-0
    WSL2_GUI_APPS_ENABLED=1
    WSLENV=WT_SESSION::WT_PROFILE_ID
    WSL_DISTRO_NAME=CentOSStream9
    WSL_INTEROP=/run/WSL/301_interop
    WT_PROFILE_ID='{d42969d1-4eb6-5ae3-aeea-40448e309a3c}'
    WT_SESSION=94de1071-a566-46e2-828b-cf56de7a4045
    XDG_RUNTIME_DIR=/mnt/wslg/runtime-dir
    _=/home/general0917//.bashrc
    (以下省略)
    ```
- コマンドサーチパスはPATH変数に格納されている
- コマンドには組み込みコマンドと外部コマンドがある
  - 組み込みコマンド
    - シェルに内蔵されているコマンド
    - シェルよって多少の違いが見られるが、bashの主な組み込みコマンドは次の表のとおりである
      | 変数 | 説明 |
      | ---- | ---- |
      | alias | エイリアスの作成・表示する |
      | bg | ジョブをバックグランドで実行する |
      | cd | ディレクトリを移動する |
      | echo | 引数の内容を表示する |
      | exit | シェルを終了する |
      | export | 環境変数を設定する |
      | fg | ジョブをフォアグラウンドで実行する |
      | history | コマンド履歴を表示する |
      | jobs | ジョブを表示する |
      | kill | プロセスにシグナルを送信する |
      | pwd | カレントディレクトリを表示する |
      | unalias | エイリアスを削除する |
  - 外部コマンド
    - シェルの外部に同じ名前の実行プログラムとして保存されているコマンド
    - **which**コマンドを使うと、コマンドの実行ファイルがどこにあるかを確認できる
      ```
      # コマンドの実行ファイルをがどこにあるかのコマンド書式
      which コマンド

      # dateコマンドの実行ファイルの場所を確認
      # 仮想マシンの環境によっては「/bin/date」と表示されることがある
      $ which date
      /usr/bin/date

      # /usr/bin/dateコマンドの確認
      $ ls -l /usr/bin/date
      -rwxr-xr-x 1 root root 106344 Jan  6  2023 /usr/bin/date

      # /usr/bin/dateコマンドの実行
      Thu Aug 10 02:35:28 AM JST 2023

      # 一般ユーザーのPATH変数の内容
      # これらのディレクトリ以下に格納されているファイルは、絶対パスを指定しなくても、コマンドとして実行可能
      $ echo $PATH
      /home/general0917//.local/bin:/home/general0917//bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/usr/lib/wsl/lib

      # /binディレクトリ以下のファイル
      # 
      $ ls /bin
      '['                                   lchsh                      setpriv
      addr2line                            ld                         setsid
      alias                                ld.bfd                     setterm
      appstream-compose                    ldd                        setvtrgb
      appstream-util                       ld.gold                    sftp
      apropos                              ld.so                      sg

      # ディストリビューションの設定によっては、一般ユーザーとrootユーザーとでパスの内容を変更している場合がある
      
      # あるシステムにおける一般ユーザーのPATH変数の内容
      $ echo $PATH
      /home/general0917//.local/bin:/home/general0917//bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/usr/lib/wsl/lib

      # あるシステムにおけるrootユーザーのPATH変数の内容
      /root/.local/bin:/root/bin:/home/general0917//.local/bin:/home/general0917//bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/usr/lib/wsl/lib

      # ユーザーによって違うコマンドを実行すると「command not found」が表示され、コマンドが実行できない場合がる。
      # その場合は絶対パスを指定して実行が可能
      ```

## 2 シェルスクリプト

### 2-1 シェルスクリプトの基本
- シェルスクリプトで一連のコマンド操作を自動化できる
  - シェルスクリプト
    - 実行する一連のコマンドを1つのファイルにまとめておき、そのファイルを呼び出すことで一括して実行するファイル
    - シェルスクリプトを作成する際は、ファイルの拡張子に「**.sh**」という拡張子を付けるのが一般的
    ```
    # diskmem.sh

    #!/bin/bash
    
    date >> diskmem.log
    echo "----------------------------------------------------------------------" >> diskmem.log

    df -H >> diskmem.log
    echo "----------------------------------------------------------------------" >> diskmem.log

    free -m >> diskmem.log
    echo "----------------------------------------------------------------------" >> diskmem.log
    ```
- シェルスクリプトの1行目に「#!/bin/bash」のように実行シェルを指定する
  - シェルスクリプトの決まり事
    - 「**#**」は、右側に記載すると、そこから右側の行はコメントとみなされる。
    - ただし、1行目だけは例外であり、1行目の「**#!**」はシェバンといい、どのシェルで実行コマンドを実行するかを指定する必要がある
- シェルスクリプトを実行するには、bashコマンドまたは、sourceコマンドの引数に指定するか、実行権を付けてパスを指定する
  - **bash**コマンドでの実行
    ```
    # シェルスクリプトの実行コマンド書式➀
    bash シェルスクリプトファイル

    # bashコマンドでの実行
    $ bash diskmem.sh
    ```
  - **source**コマンドでの実行
    ```
    # シェルスクリプトの実行コマンド書式➁
    source シェルスクリプトファイル

    # sourceコマンドでの実行
    $ source diskmem.sh
    ```
  - **bash**コマンドと**source**コマンドの違い
    - sourceコマンドでは、元のシェル(sourceコマンドを実行したシェル)のシェル変数をシェルスクリプト内で参照可能
    - bashコマンドでは、そのような機能がない
    ```
    # 例えば次のようなシェルがある。

    # testsscript.sh

    #!/bin/bash
    echo $var1
    var2="Linux"
    ```
      - **source**コマンドを使ってtestscript.shファイルを実行
        ```
        $ var1="CentOS"
        $ var2="Ubuntu"
        $ source testscript.sh
        CentOS

        $ echo $var2
        Linux
        ```
      - **bash**コマンドを使ってtestscript.shファイルを実行
        ```
        $ var1="CentOS"
        $ var2="Ubuntu"
        $ bash testscript.sh

        $ echo $var2
        Ubuntu
        ```
        - 上記のコマンドを比べてみるとわかるように、**source**コマンドでは、シェルスクリプト内でのシェル変数の参照は可能だが、**bash**コマンドでは、シェルスクリプト内でのシェル変数はできないことがわかる
  - 実行権を付けて実行
    - シェルスクリプトファイルにユーザー権限の実行権(**u+x**)を追加し、パス(絶対パス or カレントディレクトリを表す「.」)を指定して実行
      ```
      # シェルスクリプトの実行コマンド書式➂
      ./シェルスクリプトファイル名

      # 実行権を付けて実行
      $ chmod u+x diskmem.sh
      $ /mnt/c/Users/General/Documents/Practice/Linux/LPIC_Practice/LPICの基礎/practice_linux/diskmem.sh

      # カレントディレクトリを明示して実行
      # この場合、シェルスクリプトファイルがカレントディレクトリに存在していること
      $ ./diskmem.sh
      ```

### 2-2 引数と終了ステータス
- シェルスクリプトにも引数を指定することができる
- 引数は特殊な変数に格納され、シェルスクリプト内で利用できる
  - シェルスクリプト内で、引数を指定する場合は「**$1**」という特殊な変数に格納され、シェルスクリプト内で参照可能
  - 次の例では、「**$1**」をシェルスクリプト内に記載し、シェルスクリプトを実行
  - なお、引数を2つ以上指定する場合は、2番目の引数は「**$2**」、3番目の引数は「**$3**」...と続く
    ```
    # hello.shファイル

    #!/bin/bash
    echo "Hello, $1!!"
    ```

    ```
    # 引数を指定してシェルスクリプトを実行

    $ bash hello.sh GAT-X207
    Hello, GAT-X207!!
    ```
- コマンド実行の成功・不成功は終了ステータスで確認できる
  - 終了ステータス
    - コマンドに変数「**$?**」を使用すると**終了ステータス**を確認することができる
      - コマンドの実行が成功なら「**0**」
      - コマンドの実行が失敗なら「0」以外の数値
      ```
      # 終了ステータスの確認(正常終了)
      # 出力が「0」であれば、正常終了
      $ echo $?
      0
      
      # 終了ステータスの確認(エラー)
      $ ls xxxx
      ls: cannot access 'xxxx': No such file or directory

      $ echo $?
      2

      # 上記のコマンドを比べる通り、正常にコマンドが成功されたときは「0」が出力され、エラーの場合は「0」以外が出力される
      ```