---
# System prepended metadata

title: shell
tags: [' TODO', Unix-like]

---

---
tags: Unix-like, TODO
---
# shell

[TOC]

文字介面的 shell 優點：

 * 傳輸速度快
 * 較不容易出現斷線或者是資訊外流的問題

**shell 有許多的版本**，每一種 Shell 都各有其特點。

 * **sh**：Bourne Shell，由 Steven Bourne 發展，第一個流行的 shell
 * **csh**：C shell，語法有點類似 C 語言
 * **bash**：Bourne Again Shell（bash），是 Linux 使用的版本，sh 的增強版本。

## 查看可用的 shell

```shell
$ cat /etc/shells
# List of acceptable shells for chpass(1).
# Ftpd will not allow users to connect who are not using
# one of these shells.

/bin/bash  # 預設的 shell
/bin/csh
/bin/ksh
/bin/sh
/bin/tcsh  # 整合 C Shell，提供更多的功能
/bin/zsh
```

> 使用者預設的 shell 記錄在 [`/etc/passwd`](https://hackmd.io/JaR3BbMfSe6FwEIdcwStuw#etcpasswd) 內。

## `chsh`

變更使用的 shell。

```shell
$ chsh -s /bin/bash
```

## bash

bash 是 Linux 預設的 shell，相容於 sh。

優點：

 * **命令編修能力 history**
   記憶使用過的指令，上下鍵就可以找到前後一個輸入的指令。本次登入的指令記錄在記憶體，登出後才會被記在 `~/.bash_history`。

 * **命令與檔案補全功能 tab**
   Tab 自動補字。
   
 * **命令別名設定功能 alias**
   `$ alias` 可以查看到許多別名的設定。

 * **工作控制、前景背景控制 job control, foreground, background**
   > TODO：[第十六章 Linux 程序控制](http://linux.vbird.org/linux_basic/0440processcontrol.php)[color=red]

 * **程式化腳本 shell scripts**
   > TODO：[shell scripts](http://linux.vbird.org/linux_basic/0340bashshell-scripts.php)[color=red]

 * **萬用字元 Wildcard**
   可以透過 `*.py` 查詢所有指定的檔案。

`$ type` 可以查看是否為 Bash shell 的內建命令，功能類似 `$ which`。

## login 與 non-login shell

### Login shell

![](https://i.imgur.com/bZZpfGf.png)

#### `/etc/profile`

bash 的 login shell 情況下所讀取的**整體環境設定檔**其實只有 `/etc/profile`，但是 `/etc/profile` 還會呼叫出其他的設定檔。

#### `~/.bash_profile`

**個人偏好設定檔**其實主要有三個，依序分別是：

 - `~/.bash_profile`
 - `~/.bash_login`
 - `~/.profile`

其實 bash 的 login shell 設定只會讀取上面三個檔案的其中一個，而讀取的順序則是依照上面的順序。

### Non-login shell

#### `~/.bashrc`

### `$ source`

設定檔都是在取得 login shell 的時候才會讀取，可以用 `source` 馬上生效設定檔。

## 快捷鍵

 * `Ctrl-u` / `Ctrl-k` ：向前、向後刪除指令串。
 * `Ctrl-a` / `Ctrl-e` ：指標移到最前、最後。

## `$PATH`

 * 不同身份使用者預設的 PATH 不同
 * `$PATH` 由一堆目錄組成，以冒號隔開。可以透過設定變數增加目錄。

   ```shell
   $ PATH='${PATH}:<New directory>'
   ```

### 執行指令步驟

1. 執行一個指令。
2. 系統會依照 `$PATH` 去每個目錄下搜尋可執行檔，先被搜尋到的先執行。

## 變數

通常大寫字元為系統預設變數，自行設定變數可以使用小寫字元，方便判斷。

### 查看所有變數

 * `$ set`：含環境變數與自訂變數。
 * `$ env`：僅環境變數。

幾個特別的變數：

 * `?` ：上個執行完指令的回傳值，成功會回傳 0，失敗則回傳錯誤代碼。
 * `$` ：這個 shell 所使用的 PID。
 * `PS1` ：命令提示字元，`預設的 [\u@\h \W]\$` 顯示出來會是 `[celineyeh@host ~]$`

### 設定變數

```shell
$ num=1+1
$ echo $num
1+1

$ declare -i num=1+1  # 數值運算，僅能達到整數，所以 1/3 結果是 0
$ echo $num
2
```

 * `-a` ：陣列
 * `-i` ：整數
 * `-x` ：環境變數

### 字串包含變數

```shell
$ echo "lang is $LANG"
lang is zh_TW.UTF-8

$ echo 'lang is $LANG'
lang is $LANG
```

### 包含呼叫指令

```shell
$ echo $(users)
celineyeh

$ echo `users`
celineyeh

$ echo "I am `users`"
I am celineyeh
```

### 自訂變數 → 環境變數

子程序僅會繼承父程序的環境變數，不會繼承父程序的自訂變數。所以若該變數需要在其他子程序執行，則需要以 `$ export` 來使變數變成環境變數。

### 取消變數

`$ unset` 可以取消變數的設定。

## 資料流重導向 Redirect

```shell
$ echo 'hi' > test.txt      # 新建、覆蓋
$ cat test.txt
hi
$ echo 'hello' >> test.txt  # 累加
$ cat test.txt
hi
hello
```

## 判斷

 * `cmd1 && cmd2` ：你好我就好，你不好我就不好。cmd1 成功 cmd2 就執行，cmd1 失敗 cmd2 就不執行。
   ![](https://i.imgur.com/43U0BJX.png)

 * `cmd1 || cmd2` ：你不好我就好，你好我就不好。cdm1 成功 cmd2 就不執行，cmd1 失敗 cmd2 就執行，就是這麼任性。
   ![](https://i.imgur.com/q5RhZnh.png =150x)

## Pipe

![](https://i.imgur.com/xWLUgZB.png)

在每個管線後面接的第一個資料必定是能夠接受 standard input 資料的指令。

## 其他 command

 * `sort` ：排序
 * `uniq` ：將連續重複的資料僅列出一個顯示
 * `wc` ：計算行數、字數、總字數
 * [`tr`](https://linux.die.net/man/1/tr) ：刪除或替換文字

   ```shell
   $ echo 'abc' | tr [a-z] [A-Z]
   $ echo 'abc' | tr [:lower:] [:upper:]
   ABC
   ```
 * `tee` ：雙向重導向，同時將資料流分送到 file 與 stdout

   ```shell
   $ last | tee last.txt | more
   ```

 * `split` ：依照檔案大小或行數切割
 
   ```shell
   $ split [-bl] file PREFIX
   ```

## 參考資料

 * [認識與學習 BASH / 鳥哥的 Linux 私房菜](http://linux.vbird.org/linux_basic/0320bash.php)