Shell 參數
1. Shell 參數概述
在 Shell 腳本編寫中,我們為了使得程序靈活和無狀態,有些變量我們不便于在腳本中寫死,需要運用外部參數傳遞進去,每次傳遞的東西不一樣,得到的結果也不盡相同,參數是與變量相輔相成的,將參數傳遞進 Shell 腳本中,也就成了變量,參數的使用使得我們的腳本更加的靈活和可擴展,同樣也更易維護。
1.1 Shell 參數是什么
Shell 參數是我們在腳本文件外部傳入的一系列參數,或是在 Shell 腳本中給函數傳遞的參數,其實質也就是上一節我們學習的變量,其與變量相輔相成,共同組成 Shell 腳本的一部分。
1.2 為什么要用參數
我們在變量一節知道了為什么利用變量,在此原因與變量類似,參數的使用使得我們的 Shell 腳本更加靈活,不需要在腳本中寫死一些名稱,根據用戶的輸出完成特定的功能,例如編寫腳本計算 100 內數字的和,但是如果我們想計算 1000 呢?100000 呢?每次都需要修改腳本么,我們可以利用參數傳遞進計算腳本中,這樣需要計算多少就由我們自己控制,這樣的腳本也更加靈活,參數賦予腳本更強大的功能。
2. Shell 參數分類
我們知道了 Shell 中參數是什么,來看一下 Shell 腳本中參數的分類。
2.1 位置參數
位置參數顧名思義,就是傳遞給腳本參數的位置,例如給一個腳本傳遞一個參數,我們可以在 Shell 腳本內部獲取傳入的位置參數,獲取參數的格式為:$n
。n 代表一個數字。例如傳遞給腳本的第一個參數就為 $1
,第 2 個參數就為 $2
, 以此類推……,其中 $0
為該腳本的名稱。
在我們講解變量的時候,變量的一條規范就是名字不能以數字開頭,在此就是為了避免與 Shell 的位置參數相同引發異常。
例如:
[root@master Shell_args]# cat args1.sh
#!/bin/bash
echo "第一個參數為: $1"
echo "第二個參數為: $2"
echo "腳本名稱為: $0"
[root@master Shell_args]# bash args1.sh python go
第一個參數為: python
第二個參數為: go
腳本名稱為: args1.sh
我們可以看到傳遞給 args1.sh
腳本兩個位置參數,第一個為 python
, 第二個為 go
, 腳本名稱為 args1.sh
2.2 特殊參數
在 Shell 中也存在特殊含義的參數如下表:
變量 | 含義 |
---|---|
$# | 傳遞給腳本或函數的參數個數總和 |
$* | 傳遞給腳本或函數的所有參數,當被雙引號 " " 包含時,所有的位置參數被看做一個字符串 |
$@ | 傳遞給腳本或函數的所有參數,當被雙引號 " " 包含時,每個位置參數被看做獨立的字符串 |
$? | 上個命令的退出狀態,或函數的返回值,0 為執行成功,非 0 則為執行失敗 |
$$ | 當前 Shell 進程 ID。對于 Shell 腳本,就是這些腳本所在的進程 ID。 |
示例:
[root@master Shell_args]# cat args2.sh
#!/bin/bash
echo "第一個參數為: $1"
echo "第二個參數為: $2"
echo "腳本名稱為: $0"
echo "腳本接受參數總數為: $#"
curl -I baidu.com
echo "運行命令的狀態為:$?"
echo "腳本的ID為:$$"
echo "\$*的結果為:$*"
echo "\$@的結果為:$@"
for i in "$*";
do
echo $i
done
for j in "$@";
do
echo $j
done
# 運行腳本來進行測試
[root@master Shell_args]# bash args2.sh go python Shell
第一個參數為: go
第二個參數為: python
腳本名稱為: args2.sh
腳本接收參數總數為: 3
HTTP/1.1 200 OK
Date: Sun, 08 Mar 2020 07:32:22 GMT
Server: Apache
Last-Modified: Tue, 12 Jan 2010 13:48:00 GMT
ETag: "51-47cf7e6ee8400"
Accept-Ranges: bytes
Content-Length: 81
Cache-Control: max-age=86400
Expires: Mon, 09 Mar 2020 07:32:22 GMT
Connection: Keep-Alive
Content-Type: text/html
運行命令的狀態為:0
腳本的ID為:23333
$*的結果為:go python Shell
$@的結果為:go python Shell
go python Shell
go
python
Shell
我們能夠通過上述例子看出,運行 curl -I baidu.com
的輸出為 0,即為命令運行正常,獲取到了正常的返回值;
$@
與 $*
看上去很像,都是傳遞給腳本或函數的所有參數;
$*
當被雙引號 " "
包含時,所有的位置參數被看做一個字符串,我們用 for 循環遍歷的時候可以看到輸出為一行;
$@
當被雙引號 " "
包含時,每個位置參數被看做獨立的字符串,我們用 for 循環遍歷的時候可以看到為每個字符串輸出為單獨的一行。
3. Shell 參數的使用
3.1 腳本傳遞
腳本傳遞參數,就是在運行腳本的時候通過位置參數傳遞進腳本內,每個參數利用一個空格來進行分割,如果傳遞的參數本身就有空格,則可以利用 ""
來引起來,作為一個整體傳遞,在腳本內通過 $n
來獲取。
[root@master Shell_args]# cat args1.sh
#!/bin/bash
echo "第一個參數為: $1"
echo "第二個參數為: $2"
echo "腳本名稱為: $0"
[root@master Shell_args]# bash args1.sh go "python Shell java"
第一個參數為: go
第二個參數為: python Shell java
腳本名稱為: args1.sh
例如我們第二個參數為一個帶有空格的多個字符串,我們可以用雙引號引起來作為一個位置參數進行傳入。
3.2 函數傳遞
顧名思義,參數傳遞就是在函數外部進行參數的傳入,由于函數部分在后續有專門章節詳解,在此我們就以一個簡單的示例進行說明。函數傳遞與腳本傳遞非常類似,只是在調用函數的時候進行傳遞位置參數即可,例如:
[root@master Shell_args]# cat args_fun.sh
#!/bin/bash
# 函數定義
function show_args() {
echo "第一個參數為: $1"
echo "第二個參數為: $2"
echo "腳本名稱為: $0"
}
# 函數調用
show_args go Shell
[root@master Shell_args]# bash args_fun.sh
第一個參數為: go
第二個參數為: Shell
腳本名稱為: args_fun.sh
在示例中,我們可以看到沒有通過在腳本外部進行參數傳遞,而是在調用 show_args
函數的時候傳入來兩個參數。
4. 實例
4.1 需求
我們來做一個內網批量掃描可用 IP 腳本,用來判斷某一個網段中的網絡可達性。
4.2 思路
可以利用 ping
命令來檢測可以 ping 通的 IP,將返回正常的內容記錄在 success.log
中,失敗的內容記錄在 fail.log
中。
傳遞兩個參數,第一個參數為網絡前綴,例如 192.168.0.
,然后在腳本內部循環 1-255
來檢測。
第二個參數為 ping 包的個數,如果包太多,時間花費太長,太短有可能造成誤判,在此我們建議使用 2 個包來判斷。
4.3 實現
[root@master Shell_args]# cat ping.sh
#!/bin/bash
# Description: net check scripts
# Auth: kaliarch
# Email: [email protected]
# function: net check
# Date: 2020-03-08 14:00
# Version: 1.0
# 日志目錄
LOG_DIR="/tmp/netlog/"
# 如果日志目錄不存在則創建
[ ! -d ${LOG_DIR} ] && mkdir -p ${LOG_DIR}
# 定義成功與失敗日志文件
SUCCESS_LOGFILE="success.log"
FAIL_LOGFILE="fail.log"
# 網絡前綴
NET_PREFIX=$1
# 檢測包數量
PACKAGE_NUM=$2
for num in `seq 1 255`;
do
# 進行ping檢測
echo "check ${NET_PREFIX}${num}..."
ping -c ${PACKAGE_NUM} ${NET_PREFIX}${num} &>/dev/null
# 如果返回正常則記錄可以ping通的ip到successlog中
[ $? -eq 0 ] && echo ${NET_PREFIX}${num} >> ${LOG_DIR}${SUCCESS_LOGFILE} || echo ${NET_PREFIX}${num} >> ${LOG_DIR}${FAIL_LOGFILE}
done
# 測試
[root@master Shell_args]# bash ping.sh 172.16.60. 2
check 172.16.60.1...
check 172.16.60.2...
check 172.16.60.3...
check 172.16.60.4...
check 172.16.60.5...
check 172.16.60.6...
當腳本運行完成后,可以在 /tmp/netlog/
目錄下查看成功與失敗的 IP 信息。
5. 注意事項
- 需要在實戰中理解參數的特殊用處,在編寫腳本中盡可能多用參數,使得腳本無狀態;
- 需要理解
$@
與$*
兩個的不同之處,在使用循環的時候需要格外注意; - 在利用位置參數傳入腳本的時候,最好利用變量去接收傳遞的外部位置參數,便于我們在腳本內識別參數的具體含義。
6. 小結
參數與變量是相輔相成的,將變量傳遞進腳本或函數就為參數,腳本與變量配合使得我們的腳本更加通用,適應更廣的需求。需要牢記特殊參數的形式,在后期的 Shell 編程中,這些參數是腳本編程的基石,只有基礎牢靠,后續的使用才會得心應手,對上述的例子可以舉一反三,例如探測某一個 IP 的所有端口是否開放等,在實際應用場景中熟悉各種參數的用法。