<style> .blue { color: blue; } </style> # Shell ## shortcut - Bash enables emacs mode in default (you can change to vi mode) - [emacs mode shortcut](https://gist.github.com/tuxfight3r/60051ac67c5f0445efee) - emacs, Editor Macros, is a family of text editors. - characterize: extensibility ## Interactive shell, Login shell, 環境變數讀取流程 - Linux 中根據不同的情境有不同種類的 shell,在啟動時會讀取不同的設定檔 - 所以不同類型的情境,可能有不一樣的環境變數或是 shell 設定 https://ithelp.ithome.com.tw/articles/10232226 https://blog.csdn.net/Solomon1558/article/details/51763751 ### Interactive & Non-Interactive Shell - **Interactive Shell** - 使用者可以即時互動的 shell,也就是平常使用的狀態 - 從 Console 或 SSH 操作都是 Interactive Shell - 存在環境變數 **`PS1`**,代表使用者的提示詞 (Prompt, 例如 `$` 和 `#`) - 會輸出使用者的提示字,並等待使用者輸入的指令 - 使用者可以看到指令的輸出,並在一個指令結束後執行下個指令 - <font class="blue">啟動時讀取 **bashrc** 設定檔</font> - **Non-Interactive Shell** - 不需要進行互動的 Shell - 不會輸出任何的提示字 - 也不會等待使用者的輸入 - 通常被自動化和批次處理的程式使用 - 透過 `bash -c <command>` 執行的指令 - Shell Script 執行的指令 - 由程式或服務 (背景程式) 執行的指令 - 不會讀取 bashrc 設定檔 ### bashrc - 如果 **shell 是 interactive shell**,會執行 *bashrc* - *bashrc* 本身也是一個 script - 用來初始化和使用者相關的自定義變數和設定 - `PS1` 環境變數,代表 shell 的提示字 - `PATH` 變數及其他環境變數 - Shell 的 highlight、預設選項、錯誤訊息等 - 指令別名 (alias) - 有全域和使用者兩種設定檔 - **全域**的 bashrc 會作用於系統中的所有使用者 - 路徑通常是 /etc/bash.bashrc 或是 /etc/bashrc - **使用者**的 bashrc 只作用在單一個使用者 - 檔案在該使用者的 home 目錄底下 (~/.bashrc) - **bashrc 只有 shell 啟動時會被執行一次** - 如果修改 bashrc 的內容,想要馬上啟用新的設定,需要用 `source` 指令讀取新的設定 ``` source ~/.bashrc ``` ### Login and Non-Login - **Login Shell** - 存取 shell 時需要經過完整的登入流程 - 通常有輸入帳號和密碼時,就是 login shell - 從 console 或 SSH 登入時 - 使用 `su` 指令以其他使用者身分使用 shell 時 - **例外**: 使用 SSH 遠端執行指令 ```bash ssh user@host <command> ``` - 可以直接在遠端執行指令 - 需要輸入使用者密碼 - 但不屬於 login shell - <font class="blue">會讀取 **profile** 設定檔</font> - **Non-login Shell** - 不需要登入就可以存取 - 通常是在已登入的情況下,額外開啟的 shell - tmux 開啟 pane - 在 GUI 環境下,開啟 terminal 視窗 - 不讀取 profile 設定檔 ### profile - 如果 shell 是 login shell,會執行 profile - profile 本身也是 script - 用來**初始化環境變數和設定**,且只在使用者登入時執行 - 通常用來載入其他的設定檔,會根據實際情況啟動不同檔案 - 根據實際情況設定一些環境變數,例如 `PATH` 和 `PS1` - 判斷使用者身分,設定基本的提示字 (root: `#`, other: `$`) - 有全域和使用者兩個設定檔 - 全域的 profile 會作用於系統中的所有使用者 - 路徑通常是 /etc/profile - 使用者的 profile 只作用在單一個使用者 - 檔案在該使用者的 home 目錄底下 (~/.profile) ### 載入順序 ![](https://i.imgur.com/gl0gkke.png) ![](https://i.imgur.com/QunpUp3.png =500x) ## Job management https://zq99299.github.io/linux-tutorial/tutorial-basis/16/02.html ## Special Env Vars BASH裡面有一些特別的環境變數,以下幾個是我用過的: - TZ - PS1 - HOME - HOSTNAME - IFS - PATH - LANG - PWD - TMPDIR - LD_LIBRARY_PATH 說明請參考: https://www.shell-tips.com/bash/environment-variables/#gsc.tab=0 ## 特殊符號 ### 背景執行 & ``` <command> & ``` - 讓 command 在背景執行 - Command 執行的過程中,使用者可以繼續執行其他指令 - 但還是有 SSH **斷線就停止執行**的問題 - 無法取代 tmux - 但是可以讓 shell 使用較有彈性 - 參考上述的Job management相關內容 ### 指令換行 \ ``` <command part1> \ <command part2> \ ... ``` - 把一行指令 (包含用其他符號串接的多個指令) 分成多行 - 提升可讀性,或是分段輸入指令 - 舉例來說,下面的兩個寫法有相同的效果 ```bash sudo apt install build-essential vim libopenmpi-dev ``` ```bash sudo apt install \ build-essential vim \ libopenmpi-dev ``` ## 執行多個指令 - 這幾個符號可以串接多個指令 - 但是指令之間的輸入和輸出不會直接互相影響 ### 執行所有指令 ; ``` command1 ; command2 ... ``` - 不論什麼情況,所有指令都會被執行 ### 成功才會往下執行 && ``` command1 && command2 ``` - `command1` **執行成功**,才會執行 `command2` ### 失敗才會往下執行 || ``` command1 || command2 ``` - `command1` **執行失敗**,才會執行 `command2` ## Pipe - 可以把多個指令互相串接 - 並且把指令的輸出當作下一個指令的輸入 ### 標準輸出到檔案 > 或 >> ```bash command > file # 或是 command >> file ``` - 可以把指令的標準輸出,儲存到檔案中 - `>` 會把取代檔案中原本的內容 - `>>` 會把輸出內容接在檔案內容之後 ### 標準輸出到標準輸入 | ```bash command1 | command2 ``` - `command1` 的輸出會被當作 `command2` 的輸入 ### 檔案到標準輸入 < ```bash command < file ``` - 檔案中的內容會被當作指令的輸入 ## stdout 和 stderr - 程式一般的輸出都屬於 stdout - 例如: `printf()`, `console.log()`, `echo` ... - 輸出錯誤訊息時可能使用其他的 function,讓訊息透過 stderr 顯示到 terminal 上 在 Linux 中使用編號代表不同的 I/O stream - 0: stdin - 1: stdout - 2: stderr `>` 和 `>>` 預設只會把標準輸出導向到檔案中,如果要把 stderr 的的訊息存在檔案中,需要指定要被重新導向的 I/O ### 指定重新導向的 I/O stream - 在 `>` 之前加上數字,可以指定要被導向的 stream - 1 表示 stdout,所以下面兩行的意義相同 ``` command > file.txt command 1> file.txt ``` - `2>` 表示**重新導向 stderr** ``` command 2> error.txt ``` - `1>` 和 `2>` 可以結合使用,**分別儲存正常的輸出**結果和**錯誤訊息** ``` command 1> output.txt 2> error.txt ``` - `/dev/null` 是一個特殊的檔案,會無視任何輸入的資料,可以把 stderr 導向該檔案,**隱藏指令的錯誤訊息** ``` command 2> /dev/null ``` - stderr 的訊息可以導向到 stdout,該指令的 stdout 就會包含**所有的輸出資訊** (stderr + stdout),等同一般情況下輸出在**螢幕上的所有內容** ``` command > file 2>&1 # 或是 command > 2>&1 file ``` ## Problems - Search which file's content contains string `ubuntu` in /etc ```bash= #!/bin/bash echo "Enter directory path:" read directory echo "Enter keyword to search for:" read keyword # 檢查 directory 是否是目錄 if [ -d "$directory" ]; then # -type f: 表示查找的是文件而不是目錄 # -exec: 讓我們將搜尋出來的結果,使用其他的指令進行後續的處理動作 # {}: 代表找到的文件 find "$directory" -type f -exec grep -q "$keyword" {} \; # 表示有成功找到關鍵字 if [ $? -eq 0 ]; then echo "Files containing 'keyword' in $directory." find "$directory" -type f -exec grep -l "$keyword" {} \; else echo "No files found containing 'keyword' in $directory." fi else echo "Directory not found: $directory" fi ``` or ```bash= #!/bin/bash echo "Enter directory path:" read directory echo "Enter keyword to search for:" read keyword # 檢查 directory 是否是目錄 if [ -d "$directory" ]; then grep -lr $keyword $directory else echo "Directory not found: $directory" fi ``` - Find the largest file in / and its sub directory. - follow /var/log/dmesg (show the new message on console when it's been written) - show the remaining disk space size and inode count ### Meeting 提出的問題及建議 - 當初設計時,為什麼要切分成 (non-)login、(non-)iteractive shell - 彭: - 環境變數的繼承:為何有時改了某個shell中的環境變數,卻影響到其他種類的shell? - Ans: Linux processes 為樹狀結構,PID 1 之部分性質會繼承給其他process。因此,有時環境變數會被其他shell繼承。 - Shell script 之訓練,建議先閱讀他人腳本。某些腳本寫法上會較嚴謹、繁瑣,因為需支援較舊bash版本等。可多看新奇、特殊的寫法。理解script 在大型程式中發揮的作用(如:與自動化的關係等) - ubuntu 無法使用 apt update: - 安裝 ubuntu 後,使用 `apt update` 命令,出現 `E: Some index files failed to download. They have been ignored, or old ones used instead.` - 先前的情況: - 使用 `ubuntu-18.04.6-desktop-amd64.iso` 「不會」遇到此問題 - 使用 `ubuntu-22.04.2-live-server-amd64.iso` 或 `server-22-amd64.iso` 「會」遇到此問題 - meeting 當日情況: - 嘗試 `ping 1.1.1.1`,可行 - 嘗試 `apt update` 可行 - 學長建議:猜測理由,使用top-down或buttom-up測試問題出在哪個環節,如: ping, DNS, root CA... ---