Overview of Content
本文將介紹 Shell 腳本中在讀取選項(Option
)跟變數時常用的指令
無論是從基礎的 basename
和 shift
指令開始,還是深入探討處理 options 的不同方法,包括手動處理、使用 getopt
和 getopts
命令,都將一覽無遺。此外,您還將了解如何使用 read
命令從鍵盤或 Pipe 中讀取輸入
寫文章分享不易,如有引用參考請詳註出處,如有指導、意見歡迎留言(如果覺得寫得好也請給我一些支持),感謝 😀
個人程式分享時比較注重「縮排」,所以可能不適合手機的排版閱讀,建議切換至「電腦版」、「平板版」視窗看
處理 Shell 參數
以下介紹如何透過特定的命來來取得輸入給 shell 的參數;參數輸入給 Shell script 的方式如下所示
# 腳本名為「hello_script.sh」
# 參數為 「10 Apple 20 Banana」
./hello_script.sh 10 Apple 20 Banana
而接下來我們就要去獲取輸入給 hello_script.sh
腳本的參數
basename 命令:取得腳本名、基礎名
● 我們知道腳本名參數是 $0
,可以透過它取得腳本名稱;當使用者傳入完整路徑時,我們 可以用 basename
命令取出 不包含路徑的腳本名
也就是 basename
命令可以單取出腳本、參數的基礎名稱
#!/bin/bash
# 包含相對路徑來取得腳本名
echo "The script name: $0"
# 不包含相對路徑,只輸出腳本名稱
echo "The script name, and use 'basename': $( basename $0 )"
# 為輸入 $1 參數
name=$( basename $1 )
# 使用 basename 取出參數的腳本名
echo "The total path($1), and use 'basename': $name"
以下範例腳本名為
./read_cmd_2.sh
,參數為$PWD/read_cmd_2.sh
● basename
也可以 用來消除副檔名,使用方式如下
以下範例直接使用
basename
命令,並對其輸入兩個參數hello.sh
、.sh
basename hello.sh .sh
更近一步使用的範例:使用它來轉換所有 gif
成為 png
檔
#!/bin/sh
for file in *.gif; do
if [ ! -f $file]; then
echo "The ($file) is not a file."
fi
fileName=$(basename $file .git)
echo "Converting $fileName.git to $fileName.png"
giftopnm $fileName.git | pnmtopng > $fileName.png
done
shift 命令:移動輸入變量
● shift 命令的功能:
將除了腳本名 ($0
) 之外的參數全部向左移動一個位置;這個命令最常用在 當我們不知道使用者對腳本輸入多少參數時,我們可以一個參數一個參數處理、判斷
shift 預設的偏移量為 1,但它也可以一次性偏移多個位置
shift [偏移量=1]
● shift 移除的注意事項:
被移除的參數就不存在,無法再次取得,如果有顧慮的話可以先用副本參數本存(可以存為另一個參數)
●
shift
命令的使用範例:以下範例,一次移動輸入參數的兩個偏移量
#!/bin/bash varCount=0 while [ -n "$1" ] ; do (( varCount++ )) echo "Parameter #$varCount = $1" # 移動兩個參數 shift 2 done
從下圖結果中,我們也可以看到,對腳本輸入的參數為
1 2 3 a b c
,如果一次移動兩個偏移量時,就會輸出為1 3 b
處理 Shell options
在使用其他命令時常常會有 options
功能(可選功能),腳本接到 options 功能後會依照設定去處理
e.g: ls -l
其中 ls 是命令,而-l
就是 options
標準 Options
● Linux 每個命令的指令 options 的意義都不同,但它有一些大部分 options 代表的意義(不代表全部),我們可以透過這些標準 options 來猜測這個命令的使用
options | 說明 |
---|---|
-a | 顯示所有對象 |
-c | 生成一個計數 |
-d | 指定一個目錄 |
-e | 擴展一個對象 |
-f | 指定讀入數據的文件 |
-h | 顯示命令的幫助信息 |
-i | 忽略文本大小寫 |
-l | 產生輸出的長格式版本 |
-n | 使用非交互模式(批處理) |
-o | 將所有輸出重定向到的指定的輸出文件 |
-q | 以安靜模式運行 |
-r | 遞歸地處理目錄和文件 |
-x | 排除某個對象 |
-y | 對所有問題回答 yes |
命令完整的 options 建議使用
man
or--help
查詢
手動處理 options:使用 while、case、shift
● 使用 1. while
語句、2. case-in
語句、3. shift
命令,組成不斷接收判斷 options 的腳本
以下範例會取出所有對腳本的輸入,並且 case
先指定處理 -a
、-b
這兩個 options,其他的 options 則輸出 illegal option
#!/bin/bash
# 參數不為空的狀況,就持續執行 while
# `-n` 是 字串長度非 0
while [ -n "$1" ] ; do
case "$1" in
-a) echo "Get option of -a" ;;
-b) echo "Get option of -b" ;;
*) echo "$1 is not illegal option" ;;
esac
# 位移輸入參數
shift
done
從下圖中,我們可以看到輸入的參數為 -a -b -c -d
這些 options,而處理的則只有 -a -b
兩個 options
雙破折號:分離 options & 參數
● Linux Shell 中的雙破折號(--
)功能:
用來表示 options 列表已經結束,之後的皆是參數,概念程式如下所示…
# 命令 `add`
# option `-a`
# params `1`、`2`
add -a -- 1 2
● 添加了判斷雙破折(--
)符號,並在判斷是雙破折號後就 break 迴圈,代表已經處理完全的 options,接下來要處理的就是參數;範例如下…
#!/bin/bash
# 處理 Options
while [ -n "$1" ] ; do
case "$1" in
-a) echo "Get option of -a" ;;
-b) echo "Get option of -b" ;;
# 處理完 Options
--) shift
break;;
*) echo "$1 is not illegal option" ;;
esac
# 位移,移除處理完畢的 option
shift
done
# 開始處理參數,透過 $@ 取得剩餘的所有參數
for param in $@ ; do
echo "param: $param"
done
以下範例會分為「Options」、「參數」兩個分開管理
下圖中,我們對腳本 handle_options_2.sh
輸入… Options -a -b -c
、參數 11 22 33
,並且中間使用 --
號隔開
處理 options 指定的參數
● 當 option 之後有指定的參數,那在讀取完 options、參數之後,記得使用 shift
命令位移
以下範例,我們會對 handle_options_3.sh
腳本輸入幾個 Option,而我們就是要取得指定 Option 之後的參數,指定 Option 如下
● Option -a
之後 1 個參數
● Option -b
之後 2 個參數為
#!/bin/bash
# `handle_options_3.sh` 腳本
while [ -n "$1" ] ; do
case "$1" in
-a) echo "Get option of -a, param=($2)"
# 取得 -a 之後的參數後,使用 shift 移除參數
shift ;;
-b) echo "Get option of -b, param=($2, $3)"
# 取得 -b 之後的兩個參數後,使用 shift 移除兩個參數
shift 2 ;;
--) shift
break ;;
*) echo "$1 is not illegal option" ;;
esac
# 移除處理完畢的 option
shift
done
for param in $@ ; do
echo "param: $param"
done
下圖中,我們對handle_options_3.sh
腳本輸入,Option -a
之後的參數為 27
、Option -b
之後的參數為 34 "Hello"
getopt 命令:格式化輸入
● getopt
命令是一種 格式化字串的命令(將字串依照命令格式進行格式化);getopt
命令格式如下
opstring 在可以指定需要的 options 格式
getopt opstring parameters
接下來解釋如何使用
A. getopt
的 opstring
用來格式化輸入,也就是指定如處理輸入
# 規定 options 有:`a`、`b`、`c`、`d` 四個
#
# `b:` 代表 b 後面有一個參數,而 `a`、`c`、`d` 選項後沒有參數
getopt ab:cd -a -b test1 -cde test2 test3
B. getopt
添加 -q
:可以省略錯誤資訊
getopt ab:cd -a -b test1 -cde test2 test3
● 如果要使用長指令 getopt 命令要修改為
getopt -q -a --long-option-name
●
set
替換輸入命令:set 命令中有一個選項(options)就是是雙破折號(
--
),它會將命令行參數替換成 set 命令的命令行值#!/bin/bash echo "param: $1" set -- "Hello world" echo "after set, param: $1"
也就是說使用
set -- <替換數值>
,這個「替換數值」就會替代原來的輸入數據;使用set --
的範例如下下圖中,我們對
set_cmd.sh
腳本輸入123
參數,在經過命令替換後,我們可以看到輸入命令被改為 "Hello world"
● getopt
命令的使用範例:
在這個腳本中,我們先使用 set --
命令替換,替換使用者的輸入為 getopt -q a:b: "$@"
(這個動作就是在做輸入參數格式化)
格式化輸入後就可以用來上面的 while、case、shift 命令來處理輸入
#!/bin/bash
# 格式化輸入
set -- $( getopt -q a:b: "$@" )
echo "After getopt: $*"
# 處理 Options
while [ -n "$1" ] ; do
case "$1" in
-a) echo "Get option of -a, param=($2)"
shift ;;
-b) echo "Get option of -b, param=($2)"
shift ;;
--) shift
break ;;
*) echo "$1 is not illegal option" ;;
esac
shift
done
# 處理剩餘的參數
for param in $@ ; do
echo "param: $param"
done
getopt 無法讀取超過一個參數,讀取超過一個參數會出錯!
getopts 命令:加強 getopt 命令、自動處理輸入
請注意這個命令與
getopt
命令不同,它多了s
!
● getopts
命令,它有幾個特點… 首先先來看看 getopts
命令的格式
getopt opstring parameters
A. 變數的處理 不再透過 set --
處理,getopts
命令會自動將參數一個一個處理,參數處理結果成功會產生一個退出碼 0
getopts
會使用「opt
關鍵字」來處理使用者輸入的字串
使用
getopts
命令後不需要使用shift
移動
B. 使用環境變量 $OPTIND
:$OPTIND
表示當前處理到哪個變數的 index
$OPTIND
從腳本名 ($0
) 從 1 開始算;算到 參數結束
C. 使用環境變量 $OPTARG
:$OPTARG
表示當前正在處理的變數
只有有 option 時
$OPTARG
才會有值
D. 如果要省略錯誤只需要在 opstring
前,添加 :
符號
● getopts
命令的使用範例:
#!/bin/bash
while getopts :ab: opt ; do
echo "Current index: $OPTIND, arg: $OPTARG"
case "$opt" in
a) echo "Get the -a options" ;;
b) echo "Get the -b options, param: $OPTARG";;
*) echo "Other options: $OPTARG" ;;
esac
echo
done
●
getopts
仍無法取得一個 options 多個參數的狀況
●
getopts
自動分離 options 與 參數:getopts 在分析 options、參數的時候,options 與 參數 不需要空格
e.g: 我可以下命令
./getopts.sh -a -b2
,同樣可以分析出 options-b
之後接的參數是 2
取得用戶輸入
在交互式版本的腳本中常常需要使用者輸入資料,這時我們就需要取得用戶輸入,再分析使用者輸入的數據
read 命令:取得鍵盤輸入
● read
命令:
該命令可以主動反應到 Shell 要求使用者輸入資料,並讀取到腳本中,其格式如下
read options local_params
常用 Options 如下表
Options | 說明 |
---|---|
-p | 添加輸入提示 |
-t | 以秒為單位,計時限制使用者的輸入時間;超時後返回一個非零狀退出態碼 |
-n<字符數量> | 讀取指定的字符數量 |
-s | 安靜模式輸入(不會顯示使用者輸入的資訊),同常使用在輸入密碼 |
● read
命令使用範例:
A. read 基礎使用
#!/bin/bash
echo -n "Enter target file: "
read file_name
echo "Your target file is $file_name"
B. 使用輸入提示 (-p
)、限制輸入時間 (-t
)
#!/bin/bash
echo -n "Enter target file: "
read -t 5 -p "(In 5s): " file_name
if [ -z $file_name ] ; then
echo
echo "Input data too slow."
else
echo "Your target file is $file_name"
fi
C. 讀取指定字符數量 (-n
)
#!/bin/bash
read -n1 -p "Accept(Y/N): " res
echo
case $res in
Y|y)
echo "Ok, start doing." ;;
N|n)
echo "Quit!"
exit ;;
*)
echo "Unknow options($res)" ;;
esac
echo "Finish script."
D. 安靜模式輸入 (-s
)
#!/bin/bash
read -s -p "Input passwd: " pw
echo
echo "Input passwd: $pw"
read 命令:從 Pipe 讀取輸入
● Read 可以讀取 Pipe 文本直到換行(以換行做為分隔),透過這個特性就可以逐行讀取文件文本,範例如下:
以下範例透過 cat
來讀取文件,並輸入給 read
命令
#!/bin/bash
count=1
cat testFile | while read lineTxt ; do
echo "Line $count: $lineTxt"
(( count++ ))
done
更多 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 核心知識