###### tags: `tutorials` `ubuntu` `linux`
# screen 使用教學
## 介紹
`screen` 就是可以開啟一個在內部背景執行的新 shell 的指令,即使關閉 `screen` 外部 shell (main shell),`screen` 所開啟的內部 shell 只要是 detach 狀態,就仍會繼續在背景執行,也就是即使今天在電腦 A 連線 server,並以 `screen` 開啟一個 screen shell,只要電腦 A 連線 server detach 該 screen 後,到電腦 B 也可以連線至 server attach 該 screen shell
另一個好處就是,如果今天 docker container 是 execute 在 screen shell 內,如果進入不能 detach container(像是 machine learning 的 training),甚至是遇到 windows 的「善意」(自動更新並重新啟動電腦) 的時候,可以 detach screen shell,並在別的 shell re-attach
而當你要處理多種類多任務時,也建議依種類開啟多 `screen` 之後再各種類的 `screen` 內部再多開多任務的 `shell`
> 舉例來說,如果今天有需要安裝套件、建立 `docker`、執行影像辨識還有物件偵測的多種類任務,而其中要建立 2 個 `docker image`(多任務)和有 3 種關於影像辨識的測試就會像以下圖示
>
> ```graphviz
> digraph screen {
> node [shape=box]
> Base [label="Base OS"]
> screen1 [color=Brown, style=filled, fillcolor=yellow, label="安裝套件 screen\n(任務只有一個,可以不用開多 shell)"]
> screen2 [color=Blue, style=filled, fillcolor=yellow, label="docker screen"]
> screen3 [color=Red, style=filled, fillcolor=yellow, label="影像辨識 screen"]
> screen4 [color=Green, style=filled, fillcolor=yellow, label="物件偵測 screen\n(任務只有一個,可以不用開多 shell)"]
> task2_1 [color=Blue, style=filled, fillcolor=cyan, label="docker image1"]
> task2_2 [color=Blue, style=filled, fillcolor=cyan, label="docker image2"]
> task3_1 [color=Red, style=filled, fillcolor=cyan, label="影像辨識 test1"]
> task3_2 [color=Red, style=filled, fillcolor=cyan, label="影像辨識 test2"]
> task3_3 [color=Red, style=filled, fillcolor=cyan, label="影像辨識 test3"]
>
> Base->screen1 [label="開 screen"]
> Base->screen2 [label="開 screen"]
> Base->screen3 [label="開 screen"]
> Base->screen4 [label="開 screen"]
> screen2->task2_1 [label="開 shell"]
> screen2->task2_2 [label="開 shell"]
> screen3->task3_1 [label="開 shell"]
> screen3->task3_2 [label="開 shell"]
> screen3->task3_3 [label="開 shell"]
> }
> ```
> 就是只會開 4 個 `screen`,再進入個別 `screen` 依多任務開多個 `shell`(下面會介紹如何在 `screen` 中多開 `shell`),之後再依任務別在 `screen` 中切換不同任務 `shell`
:::info
進入 screen shell 後,相關的 `screen` 快捷鍵指令起手式都是先按 `ctrl + A` 然後全部放開( `ctrl` 和 `A` )再按其他按鍵
:::
## 安裝
```bash= !
$ apt-get update && apt-get install -y screen
```
## 設定 buffer 行數為 `1000000` 行
```bash= !
$ echo "defscrollback 1000000" >> ~/.screenrc
```
## Usage
### Open new screen
~~~bash= !
$ screen -S {screenName}
~~~
輸入後會提醒即將進入 screen shell 等資訊,按下 `Space` 或是 `Enter` 繼續
- -S *(optional)*: 設定 screen shell 名稱 `{screenName}`,可以不用指定,預設只有 screen shell id
- `{screenName}`: 指定的名稱
---
### Open new shell in screen
- 在 screen shell 內,按下 `ctrl + A` 後再按下 `C` (Create)
---
### Switch shell in screen
- 如果有在 screen 中開很多 shell
- 可以按下 `ctrl + A` 後再按下 `P` (Previous)或是按下 `ctrl + A` 後再按下 `backspace 鍵` 切到上一個 shell
- 可以按下 `ctrl + A` 後再按下 `N` (Next)或是按下 `ctrl + A` 後再按下 `空白鍵` 切到下一個 shell
- 可以按下 `ctrl + A` 後再按下數字鍵(`0`~`9`)切換至指定編號的 shell
- 可以按下 `ctrl + A` 後再按下 `shift + "` 顯示目前 screen 的所有 shell,並可以使用上下鍵選擇 shell
:::info
screen 中的 shell 是會循環的,也就是說例如只有開 2 個 shell,分別是 `0` 號 shell 及 `1` 號 shell,即使今天從 `0` 號 shell 切到下一個 shell,`1` 號 shell 後,再切換到下一個 shell 就會回到 `0` 號 shell
:::
---
### List screen shells
~~~bash= !
$ screen -ls
~~~
- 會列出所有 screen shell,以便知道要 re-attach 的 screen shell id
---
### Detach
- 在 screen shell 內,按下 `ctrl + A` 後再按下 `D` (Detach)
- detach 狀態的 screen shell 仍會在背景執行
- 在 screen shell 外
```bash= !
$ screen -D {screenShellId_or_screenShellName}
```
- -D: dettach 指定 screen shell
- `{screenShellId_or_screenShellName}`:
- 如果是使用 screen shell id,不一定要打完整 id,只要打到可以辨別他可以 identify 的部分就足夠
> 也就是如果 `screen -ls` 後有 `17706` 和 `17609` 兩個 screen shell,而我要 re-attach `17609` 的 screen shell,打 `screen -r 176` 即可
- 如果是用 screen shell name 則需要完整名字
---
### Re-attach
~~~bash= !
$ screen -r {screenShellId_or_screenShellName}
~~~
- -r: re-attach 指定 screen shell
- `{screenShellId_or_screenShellName}`:
- 如果是使用 screen shell id,不一定要打完整 id,只要打到可以辨別他可以 identify 的部分就足夠
> 也就是如果 `screen -ls` 後有 `17706` 和 `17609` 兩個 screen shell,而我要 re-attach `17609` 的 screen shell,打 `screen -r 176` 即可
- 如果是用 screen shell name 則需要完整名字
:::info
如果只有一個 detach shell,則可以不用打 `{screenShellId_or_screenShellName}`,也就是直接 `screen -r` 就可以 re-attach 該 screen shell
:::
---
### Close screen shell
在 screen shell 內
- 按下 `ctrl + A` 後再按下 `K`(Kill),之後會詢問是否要關閉,要再輸入 `y` 確定
---
### Terminate screen
有 3 種方式,都在 screen shell 內
1. 連續按下 `ctrl + A` 後再按下 `K`(Kill),之後會詢問是否要關閉,要再輸入 `y` 確定(關閉所有 screen shell 已離開 screen)
2. 按下 `ctrl + D`
3. 輸入 `exit`
---
### Copy mode
:::warning
在 shell screen 內,會無法看到超出螢幕畫面的 shell contents,所以如果要看被截斷的 shell content,則需要用此功能
:::
- 在 screen shell 內,有 2 種方式進入 *copy mode*
1. 按下 `ctrl + A` 後再按下 `esc`
2. 按下 `ctrl + A` 後再按下 `[`
- 可用 `方向鍵` 操作 cursor
- 可用 `/` 與 `?` 來搜尋
- 按下 `空白鍵`(或是 `Enter`) 開始選取要複製的內容,選取完成後再按下 `空白鍵`(或是 `Enter`) 即可複製選取內容
---
### Command in screen
| 按鍵 | 說明 |
|-|-|
|`ctrl + D` | 關閉目前 screen |
| `ctrl + A` 再按 `C` | 建立新的 shell |
| `ctrl + A` 再按 `ctrl + A` | 切換至上一層 screen<br>*(當在 screen 中開 screen 時使用)* |
| `ctrl + A` 再按數字鍵(`0`~`9`) | 切換至指定編號的 screen shell |
| `ctrl + A` 再按 `N` 或<br>`ctrl + A` 再按 `空白鍵` | 切換至下一個的 screen shell |
| `ctrl + A` 再按 `P` 或<br>`ctrl + A` 再按 `backspace` | 切換至上一個的 screen shell |
| `ctrl + A` 再按 `W` | 列出目前 screen 中的所有 shell |
| `ctrl + A` 再按下 `shift + "` | 顯示目前 screen 的所有 shell<BR>*可以使用上下鍵選擇 shell* |
| `ctrl + A` 再按下 `K` | 關閉目前 screen shell |
| `ctrl + A` 再按下 `D` | 卸離目前 screen |
| `ctrl + A` 再按下 `[` 或<br> `ctrl + A` 再按下 `esc` | 進入 `copy mode`<br>可用`方向鍵`操作捲軸,或用 `/` 與 `?` 來搜尋<br>按下`空白鍵`開始選取要複製的內容,選取完成後再按下第二次`空白鍵`即可複製<br>隨後使用 `ctrl + ]` 可貼上複製的內容。|
| `ctrl + A` 再按下 `S` | 將畫面分割成上下兩個區域 |
| `ctrl + A` 再按下 `Q` | 關閉分割畫面 |
| `ctrl + A` 再按下 `tab 鍵` | 切換分割畫面 |
| `ctrl + A` 再按下 `T` | 顯示目前系統的時間與負載狀況 |
| `ctrl + A` 再按下 `A` | 送出 `ctrl + A` |
| `ctrl + A` 再按下 `?` | 顯示 screen 說明 |
| `ctrl + A` 再按下 `V` | 顯示 screen 版本資訊 |
| `ctrl + A` 再按下 `X` | 鎖定 screen |
| `ctrl + A` 再按下 `H` | 開啟或結束 screen 紀錄功能 |
| `ctrl + A` 再按下 `C` | 清除 screen 視窗中的內容 |
| `ctrl + A` 再按下 `ctrl + G` | 視覺化鈴聲(visual bell)切換 |
| `ctrl + A` 再按下 `I` | 顯示目前 screen 視窗的資訊 |
| `ctrl + A` 再按下 `L` | 重繪目前 screen 視窗的內容 |
| `ctrl + A` 再按下 `:`<br>接著輸入<br> `scrollback 10000` | 將 screen 的 buffer line 設為 `10000` 行 |