Shell 字面常數、引號
在 Shell 中,不同「引號」代表的意義不同,Shell 對於命令中的引號分析如下:
A. 在執行之前 Shell 會尋找其中的變數、萬用字元、其他代數,並將其替代(至於變數部分又會與「單」、「雙」引號有關)
B. 替換完畢後,會將結果傳遞給命令
單引號:不會替換
● 要建立常數最簡單的方法(或是說標準的做法)就是使用單引號,在 單引號內的字元 不會被替換,它們將以常數的方式表現
# $ 不會被替換
echo 'Good morning~ $PLACE_HOLDER'
# * 不會被轉換
echo 'Good morning~ *'
# $() 不會啟動一個新 Shell
echo 'Good morning~ $(echo Apple)'
從下圖中,我們可以看到被單引號包裹的命令(
$PLACE_HOLDER)是不會執行的
● 被單引號括著的就是一個參數,如果要輸出單引號要使用跳脫字元(
\):有時候我們會碰到需要使用單引號
'的時候,這時就要注意,可以使用跳過字元(反斜線\)# 這句其實輸出了三個字面參數 # 1. 'I' # 2. \' (跳脫字元) # 3. 'm Alien echo 'I''\'m Aliem'
雙引號:替換、執行
● 雙引號與單引號最大的差別在,雙引號內的 特殊字元會被替換、執行
# 定義 NAME 變數
NAME=Alien
# 使用單引號呼叫變呼叫數
echo 'What up $NAME'
# 使用雙引號呼叫變呼叫數
echo "What up $NAME"
如下圖所示,變數
NAME確實會在執行時被替換
Shell 環境變量
bash shell 用一個叫作 環境變量 (environment variable) 的特性來存儲有關 shell 和工作環境的信息
變量儲存在記憶體(內存)中
Bash shell 中,環境變量主要分為兩類:1. 局部變量、2. 全局變量
讀取局部變量:set
● 局部變量只會讓創建變量的 Shell 本身訪問(其他的 Shell,包括 sub shell 也不可訪問);如果要查看全部的局部變量,可以執行以下命令
| 命令 | 說明 |
|---|---|
| set | 列出所有全局、局部變量 (並且會對變量進行排序) |
## 列出所有全局、局部變量
set
局部變量一般來說都用小寫,全局變量則使用大寫
設定/移除局部變量:unset
● 設定局部變量:簡單使用,變量名= 變量,就可以設定局部變量
echo $my_local_variable
## 設定局部變量
my_local_variable="Hello local variable."
echo $my_local_variable
## 查看局部變量
set | gerp my_local
● 設定 Shell 變量時的注意事項
A. 變量最好使用單(或雙)引號包裹起來,不然 空格會被誤認變量已設定完成
錯誤範例:my_local_variable=Hello local variable.
B. 賦予值時
=之間不要使用空格空開,否則 Shell 會解讀為單獨命令錯誤範例:my_local_variable = "Hello local variable."
● 在子進程中無法獲取父進程的局部變量;不過如果使用 進程列表 的方式創建 sub shell 就可以獲取父進程局部變量
echo $my_local_variable ## 創建 sub shell bash ## 查看進程 ps --forest ## sub shell 不可訪問 parent shell 的局部變量 echo $my_local_variable ## 退出 sub shell exit ## 回在 parent shell 就可以訪問 echo $my_local_variable
● 移除局部變量:使用 unset 命令就可以移除局部變量;移除時不需使用 $ 符號
echo $my_local_variable
## 移除局部變量
unset my_local_variable
echo $my_local_variable
## 查看局部變量
set | gerp my_local
全局變量:env/printenv
● 全局環境變量就是所有 Shell 會話都可以訪問的變量;查看全局變量的命令如下
| 命令 | 說明 |
|---|---|
| env | 列出所有全局變量 |
| printenv [指定變量] [指定變量] ... | 同上,不過它可以指定變量 |
## 只列出前 10 項全局變量
env | head
## 列出指定變量
printenv SHELL
## 可指定多個
printenv SHELL HOME
設定/移除全局變量:export
● 創建全局變量:使用 export 命令就可以創建一個全局變量 (變量創建方式與設定局部變量相同)
透過 export 創建的變量就可以讓 sub shell 訪問到
● sub shell 取得的是原本變量的參照?
不是~ sub shell 取得的是一個 變量副本,sub shell 可以改變變量的值,但是無法影響到外部變量(不會影響到原本的變量)
## 創建全局變量
export my_export_variable="Hello export variable."
echo $my_export_variable
## create sub shell
bash
## 讀取外部全局變量
echo $my_export_variable
## 修改變量副本
my_export_variable="Fix!"
## 讀取修改後的副本內容
echo $my_export_variable
## exit sub shell
exit
## 讀取外部變量(不受內部修改影響)
echo $my_export_variable
● 刪除全局變量,同樣使用 unset 命令
unset my_export_variable
Shell 特殊參數
bash 中附有幾個「特殊參數」,可以透過這些特殊參數來達到你要的功能
Shell 腳本讀取參數:$
我們可以對腳本傳入需要的參數,像是如下
# add 是腳本
# 10、20 就是參數
add 10 20
● Shell 會將輸入參數稱為 位置参數 (positional parameter),其參數有部分限制、特性:
● 參數順序以 0 開始計算!
● 第一個參數 $0 一定是腳本本身的名稱!
● 參數取用方式 $參數順序,當參數數量超過 9 時,必須要花括號來包裹 ${參數順序}
e.g:
第 3 個參數 ->
$2第 12 個參數 ->
$11
● 以下透過讓使用者輸入一個參數,實現階乘 factorial 的運算
#!/bin/bash
factorial=1
userSet=$1
for (( a = 1; a <= userSet; a++ )) ; do
(( factorial *= a ))
echo "$a: $factorial"
done
echo "The factorial of $userSet is $factorial."
● 如果你要輸入更多的參數,請使用 空格 區分不同參數
● 如果輸入的參數有包含空格,需使用單引號(雙引號也可以)包裹空格
● 使用參數時,建議使用 test 命令(
-n、-z)來測試參數是否存在,避免取不到參數的錯誤
Shell 腳本取得參數總數:$#
● $# 符號可以取得使用者輸入的參數總數,這個參數總數不包括腳本本身,也就是不包括 $0
● 符號特殊改變:
有個特殊情況,如果外部已經用「$ + 花括號,
${ }」包裹,那取參數總數的方式就會變成${!#};花括號內不能用$,要改用!使用
${!#}時,如果參數總數為 0,則輸出腳本自身
● 取得輸入給 Shell 腳本參數總數的範例:
#!/bin/bash
tpc=$#
echo "total param count = $tpc"
echo "total param count = ${!#}"
if [ $tpc -lt 2 ] ; then
echo "param too less"
elif [ $tpc -gt 2 ] ; then
echo "param too more"
else
echo "result: $[ $1 + $2 ]"
fi
Shell 腳本取得所有參數:$*、$@ 差異
● $*、$@ 兩個符號都可以取得所有參數,不過他們兩個還是有不同的地方;差異點在於對於看待參數時是否分離
| 符號 | 特點 |
|---|---|
| $* | 將所有參數視為一個個體(整體) |
| $@ | 將所有參數分開看待 |
● Shell 讀取所有參數的範例:
#!/bin/bash
for tmp in "$*" ; do
echo "\$*: $tmp"
done
for tmp in "$@" ; do
echo "\$@: $tmp"
done
從下圖中,我們可以看到 $* 確實將全部的參數視作一個整體
取得上次命令退出碼:$?
● 使用 $? 可以取得上次執行的命令的退出碼(這邊要特別注意的是,$? 符號只保存最近一次,它不會保存超過一次以上的退出碼),而取出上次命令的退出碼數值如果是 0 則代表上一次的命令執行成功,而 非 0 則代表上一次的命令失敗;範例如下…
echo "HelloWorld"
echo $?
ls 123
echo $?
自身 Shell PID:$$
● 使用 $$ 符號,就可以獲取當前使用的 Shell PID;範例如下…
echo $$
Shell 更多不同變量的變量
除了上述的基礎定義 Shell 變量的方法外,Shell 也可以定義 array 變量、默認變量、PATH 變量... 等等
Shell 數組變量:Array 變量
● 數組(Array)變量在賦予值時,是放置在括號內,並使用空格區分開;格式說明如下表
| 功能 | 格式說明 | e.g |
|---|---|---|
| 宣告 Array | 放置在括號 () 內,並使用空格 () 區分開 | MyArray=(A B C D E F G) |
| 單個值 | 數組變數放置花括號 {} 內,並使用中括號 [] 指定 | ${MyArray[2]} |
| 全部值 | 同上,不過中括號內使用 *,將全部數據視為一個數據 | ${MyArray[*]} |
| 全部值 | 同上,不過中括號內使用 @,它會將數組中的數據 單獨 展開 | ${MyArray[@]} |
| 取消變數 | 使用 unset | - |
## 宣告並設定值
MyArray=(A B C D E F G)
## 預設取出第一個
echo $MyArray
## 取單個值
echo ${MyArray[2]}
## 取全部值
echo ${MyArray[*]}
## 取消變數
unset MyArray
echo ${MyArray[*]}
● 另外一個 Shell 數組變量的宣告方式,使用大括號 {}:
大括號宣告陣列(array)還可以指定「間距」,格式為 {first..last..step},其中 step 就代表了間距;範例如下
for VAL in {0..10..2}; do; echo "$VAL"; done
默認 Shell 變量
● 默認情況下,Bash shell 會用一些特定的變量來定義系統環境 (這些特定變量就是默認 Shell 變量);以下列出幾個常見變量(默認環境變量有很多,如有需要請查表)
這些默認變量並非一定有值,有可能為空
| Shell 變量 | 功能描述 |
|---|---|
| HOME | 當前用戶目錄 |
| IFS | 用來切割文本的字符串 |
| PS1 | Shell 命令 主提示 符號 |
| PS2 | Shell 命令 次提示 符號 |
| PS3 | Select 命令 提示 符號 |
| EUID | 當前用戶的有效用戶 ID |
| BASH | 當前 Shell 實例的全路徑名 |
| BASH_ENV | Shell 腳本啟動前會嘗試運行該變量定義的 啟動文件 |
| GROUPS | 當前用戶的群組 |
● 默認變量可以使用
set指令列出但同時也要注意,不是所有默認環境變量都會在運行
set命令時列出
PATH 環境變量:暫時環境變量
● PATH 環境變量用於進行命令、程序查找的目錄;當使用外部命令時,就會去查找 PATH 變量中的路徑,並在這些路徑下找命令
echo $PATH
路徑之間使用
:隔開
● 這裡來說明,如何暫定 PATH 變量
暫時環境變量的生命週期只會依存於 Shell 的命生週期,如果 Shell 結束,這個暫定的 PATH 變量也會結束;範例如下…
echo $PATH
## 新增路徑(使用 `:` 隔開)
PATH=$PATH:/home/alien/Desktop/test
## 再次查看 PATH 就會發現有新增
echo $PATH
● 如果希望 sub shell 也可以使用自己的 PATH,那在定義時就要加入
export關鍵字export PATH=$PATH:/home/alien/Desktop/test
Shell 的啟動 & 環境變量
如果要讓環境變量永久化,那就要將環境變量設定寫入 某些文件;所以這裡我們要先來 討論 Shell 的啟動 & 環境變量的關係
● Shell 啟動一般來說有以下幾種方式
A. 登入式:登入帳號默認的登入 Shell;可以是透過 /bin/login, SSH ... 等等方式從中端登入,這些方式就稱為 登入式 Shell
每個帳號預設的 Shell
B. 交互式:非登入 Shell;如同登入帳戶後,在 Linux GUI 中開啟的 Shell
sub shell 的概念
C. 腳本式(又稱為非交互式):作為腳本運行的 Shell
腳本 Shell 其實就是文本,而文本在開頭就會指定 shell 類型;
e.g :
#!/bin/bash
Shell 提示字元
● 我們可以透過設定 PS1 變量來改變當前 Shell 視窗的提示字元
● 替換字元不要使用 Shell 關鍵字 (不要用
<、>、&、{}、=... 等等符號)
替換格式如下
PS1='<替換關鍵字>'
常用 替換關鍵字 如下
| 關鍵字 | 功能 |
|---|---|
\u | 當前使用者名 |
\h | Host 名稱 |
\! | 當前已輸入的指令號(History 統計數量) |
\w | 當前完整目錄 |
\W | 當前目錄(只有目錄,沒有全路徑) |
\$ | 依照權限顯示,如果是使用者顯示 $ 符號,如果是管理者則顯示 ! 符號 |
# User 名稱
# Host 名稱
# 指令號
# 當前目錄
# 權限顯示
PS1='\u@\h(\!)\W\$'
登入 Shell:加載順序
● 登入的 Shell 會從「5 個」不同的文件中讀取命令,而這些文件的讀取也是有順序的,順序功能如下
A. /etc/profile 內會呼叫並讀取 /etc/profile.d 目錄,該目錄會保存多個 sh 腳本
| 文件 | 功能 | 補充 |
|---|---|---|
/etc/profile | 主啟動文件 | 每個用戶登入時都會加載該文件 |
## 查找關鍵字
cat /etc/profile | gerp -A 10 profile
ls -laF /etc/profile.d/
可以發現腳本內會讀取
/etc/profile.d目錄中所有.sh結尾的文件
B. 接下來就是登入用戶後(針對用戶,可根據需求訂製),會加載的啟動文件(每個發行版使用的文件不同)
| 加載順序 | 文件 | 補充 |
|---|---|---|
| 1 | $HOME/.bash_profile | - |
| 2 | $HOME/.bash_login | - |
| 3 | $HOME/.profile | - |
| - | $HOME/.bashrc | 該文件是透過其他文件被加載 |
並非每個文件都存在,大部分 Linux 發行版都只會使用這些文件的 1 ~ 2 個
## Ubuntu 22 中是透過 `$HOME/.profile` 文件加載 `$HOME/.bashrc`
cat ./.profile | grep bashrc
交互式 Shell
● 交互式 Shell 也就是 sub shell,它在是在登入後才啟動的 Shell,所以自然不會讀取 /etc/profile 文件;
交互式 Shell 會讀取 $HOME/.bashrc 文件
cat .bashrc | grep -v -E "^#"
●
.bashrc有幾個作用A. 加載查看
/etc/bash.bashrcB. 載入用戶設定的別名 (
alias)
非交互式 Shell
● 非交互式 Shell (Shell 腳本) 啟動時會先檢查 BASH_ENV 全局變量,並去讀取它的值去加載啟動文件
printenv BASH_ENV
BASH_ENV不一定會有設定值
一般來說 sub shell 會導出父 shell 的變量來使用 (記得用 export)
永久化環境變數
● 一般來說可以寫在以下兩個文件中
| 寫入文件 | 注意事項 |
|---|---|
/etc/profile | 更新系統版本後就會被刷掉,最好是改成在 /etc/profile.d 目錄下創建一個 .sh 文件 |
$HOME/.bashrc | 可適用於大多數 Shell,如果是非交互式 Shell 則要注意 BASH_ENV 設定 |
更多 Linux Shell 知識
Linux 環境、服務:用戶、權限管理
● Linux 環境、服務、管理:
在這個主題中,你可以探索各種 Linux 環境、服務和管理相關的重要概念…
● 了解 Linux 組成:內核責任、GNU 工具、桌面環境 | 基礎版到發行版
在這裡,你將了解 Linux 系統的基本組成部分,包括內核、GNU 工具和桌面環境,並了解不同 Linux 發行版之間的差異
● 探索 X Window 服務與桌面環境:Linux 視窗 XWindow 服務、D-Bus 機制
這裡探討了 Linux 系統中 X Window 服務和 D-Bus 機制的工作原理,讓你深入了解桌面環境的背後運作方式
● Linux 系統管理入門:安全性、用戶管理與權限設定指南
在這個指南中,你將學習如何管理 Linux 系統,包括安全性、用戶管理和權限設定,以確保系統的安全和有效運作
● 認識身份驗證與權限管理:UNIX UID、使用者驗證與 PAM | PAM 設定
這裡介紹了 UNIX 系統中的身份驗證機制和權限管理方式,包括 UNIX UID、使用者驗證和 PAM(
Pluggable Authentication Modules)設定
Linux Shell 相關知識
● Linux Shell 相關知識:
這個主題涵蓋了各種與 Linux Shell 相關的知識,從基礎到進階都有…
● Shell 基礎知識:包括 Shell 的基礎使用以及差異,還有變數以及計算
● 認識命令行:Shell 類型、命令差異 | Sub Shell 關係 | Builtin 命令
這裡介紹了命令行中不同類型的 Shell,以及各種 Shell 命令之間的區別和內建命令的用法
● Shell 全局及區域變數、特殊變數及環境變數 | Shell 啟動順序 | Array 變數
學習如何在 Shell 中使用全局變數、特殊變數和環境變數,以及如何設置和管理這些變數
● 探索腳本與命令:Shell 腳本的必備相關知識 | 腳本的數學運算
這裡介紹了 Shell 腳本的基本知識和常用技巧,包括如何執行腳本和進行數學運算
● Shell 結構化
● Shell 腳本程式中的條件語句和高級特性 | Shell 結構化 & 判斷
該篇文章是介紹結構化腳本的基礎以及特殊的高級技巧,轉著於腳本中的邏輯判斷
● 掌握 Bash 腳本中的迴圈與循環控制技巧 | Shell 結構化 & 循環
接著是腳本中的循環與控制的技巧,它可以讓我們在 Shell 腳本中有更多的判斷與技巧
● 探索 Shell 函數與腳本庫 | Shell 結構化 & 函數
這裡你將會學在到結構化腳本的重要技巧「函數」,它可以讓你建立可重複利用的腳本,以節省我們之後開發的時間
● Shell 掌握參數處理與用戶輸入技巧 | Shell 結構化 &輸入互動
不可互動的腳本有時候相對無趣,這篇文章有分享如何讓腳本與使用者產生交互互動,並依照使用者輸入的參數做讀取
● Shell script 進階
● Shell 命令輸入與輸出指南:掌握標準文件描述符與重定向 | 臨時文件
掌控 Shell、指令的輸出輸入是成為進階使用 CLI 之人必經的一課,透過這篇文章可以了解到輸出輸入、臨時文件等等資訊
● 探索 Linux 訊號與後台進程管理:安排定期啟動腳本 | 運行時啟動腳本
信號可以算是 Shell 腳本與 Linux 系統之間的通訊方式,透過這個文章,我們可以了解到信號與 Shell 腳本的安排時間
Linux 硬體規劃:檔案系統、分區
● Linux 硬體規劃:檔案系統、分區:
最後,這個主題涵蓋了 Linux 系統中硬體結構相關的重要概念…
● Shell 文件和目錄操作的常用命令和技巧 | 尋找檔案
這裡介紹了 Shell 中常用的文件和目錄操作命令,包括如何尋找文件和管理文件系統
● 深入探索 Linux 文件系統與硬體管理 | 分區、檔案系統、邏輯卷 | inode
學習如何管理 Linux 文件系統,包括分區、文件系統和邏輯卷等相關概念,以及文件系統中的 inode 機制
● 理解 Unix/Linux 設備偵測、建立 | 認識與使用 udevd | SCSI 與 Linux 核心
這裡介紹了 Unix/Linux 系統中的設備偵測和管理,包括如何使用 udevd 和 SCSI 相關的 Linux 核心知識





















