一、 命令行參數
特殊環境變量 | 含義 |
$1 $2..$9,${10}... | 表示腳本的第n個參數 |
$0 basename $0 |
腳本名(含路徑) 腳本名(不含路徑) |
$# ${!#} |
參數總數 最後一個參數值 |
$* |
將所有參數作爲一個字符串保存 |
$@ | 將n個參數作爲n個字符串保存 |
向shell腳本傳遞數據最基本的方法是使用命令行參數,在腳本運行時指定參數,例如:
./add.sh 10 30
./output.sh 'Hello World' #帶空格的參數需加引號,單雙引號均可
shell提供位置參數(一組特殊環境變量集合),分別用$1 $2..$9表示第一至第九個參數,10之後寫法爲${10}。
有兩個比較特殊的參數$0和$#,$0表示執行的腳本名(含路徑),$#表示參數的個數
如果只想獲取腳本名不需要路徑,可以使用basename命令
當腳本需要輸入參數才能正常工作時,應該使用 if [ -n $1] 或者 if [ $# = 2] 判斷參數數量是否正確。
你可能會想,既然$#表示參數的個數,${$#}是不是就代表最後一個參數的值?實際上不是,shell不允許在{}中使用$符。正確的寫法應該是${!#}。
想要獲取所有命令行參數,可以使用$*或$@,$*將所有參數視爲一個字符串,$@則將每個參數視爲一個字符串。
#!/bin/bash
echo "print each param from \"\$*\""
for var in "$*"
do
echo "$var"
done
echo "print each param from \"\$@\""
for var in "$@"
do
echo "$var"
done
運行腳本
./test.sh a b c d
print each param from "$*"
a b c d
print each param from "$@"
a
b
c
d
二、 移動變量 shift
shift命令默認會將每個變量向左移一位(相當於shift 1),$3->$2,$2->$1,並刪除原$1的值。當你不確定到底會有幾個參數時,這是個好辦法,你可以只操作第一個變量,移動參數,然後繼續操作新的第一個變量。
#!/bin/bash
# 找出文件(可指定多個文件名)中長度最長的單詞,$1爲文件名
while [[ -n $1 ]] # 參數不爲空,即還有待查找文件
do
if [[ -r $1 ]];then # 文件存在且有讀權限
max_word=
max_len=0
for i in $(strings $1) # strings程序(包含在binutils包中)爲每一個文件產生一個可讀的文本格式的words列表
do
len=$(echo $i | wc -c) # wc -c統計字符數,即計算每個單詞長度
if ((len > max_len));then
max_len=$len
max_word=$i
fi
done
echo "$1:'$max_word' ($max_len characters)"
fi
shift # 參數向左偏移,即開始查找下一個文件
done
也可以利用 shift n 指定每個變量向左移幾位
#! /bin/bash
while [ -n "$1" ] # 加雙引號表示強制變量爲字符串格式,對於字符串的比較,變量取值一定要加雙引號
do
echo $1
shift 2
done
三、 選項處理
1. 單獨選項
有時腳本後不僅有參數,還有選項,例如
./mypara.sh -a -b param1 -d
最簡單的可以使用case處理選項,確定哪些選項後可能有參數,會有幾個參數,在對應case的中處理參數。
#! /bin/bash
# 假設選項有-a -b -c,僅-b後會有1個參數
while [ -n "$1" ]
do
case "$1" in
-a) echo "Found the -a option";;
-b) param="$2"
echo "Found the -b option,with parameter $param"
shift ;; #參數多佔一位,需要挪走
-c) echo "Found the -c option";;
--) shift
break ;;
*) echo "$1 is not the an option";;
esac
shift
done
2. 合併選項與getopt命令
合併選項例如 ll -rth,這時前面的方法就沒法解決問題,需要使用到 getopt 命令。
getopt 能夠識別一系列任意形式的選項和參數,並自動將它們轉爲適當格式。
getopt optstring parameters
optstring 是其中的關鍵,它定義了命令行有效的選項字母,以及哪些選項需要參數(在字母后加:),例如:
getopt ab:cd -a -b test1 -cd test2 test3
#選項有-a -b -c -d,-b後有:說明-b後面會有參數
輸出會是轉換後的格式,其中test2 test3被識別爲額外參數,用--分隔開
如何在腳本中使用getopt 命令?可以將getops命令輸出(格式化後的參數)傳給set,set -- 命令會將命令行參數替換成set命令的命令行值。
#/bin/bash
###################################
# Extract command line options & values with getopt
set -- $(getopt -q ab:cd "$@")
while [ -n "$1" ]
do
case "$1" in
-a) echo "Found the -a option" ;;
-b) param="$2"
echo "Found the -b option, with parameter value $param"
shift ;;
-c) echo "Found the -c option" ;;
--) shift
break ;;
*) echo "$1 is not option";;
esac
shift
done
#輸出額外參數
count=1
for param in "$@"
do
echo "Parameter #$count: $param"
count=$[ $count + 1 ]
done
你會發現這個腳本跟前面整體差別不大,但它提供了合併選項的處理。
但是,getopt 命令並不擅長處理帶空格和引號的參數值,例如
./mypara.sh -a -b param1 -c "test1 test2" test3
可以看到它並沒有將"test1 test2"當作整體處理,只是用空格作分隔符。
3. 更強大的getopts命令
getopts基本上是一個增強版:
- getopt 命令處理選項和命令行後只生成一個格式化的輸出,需要用set轉換,而getopts不再需要。
- getopt 命令不擅長處理帶空格和引號的參數值,而getopts可以
# 用法與getopt基本相同
getopts optstring variables
# 要忽略錯誤消息,需在optstring前加冒號:,即
getopts :optstring variables
# variables中會保存當前參數
注意getopts解析後的命令行選項不帶-,使用case匹配時也不需加,$OPTARG中存儲選項後參數
#!/bin/bash
###################################
# simple demonstration of the getopts command
#
echo
while getopts :ab:c opt
do
case "$opt" in
a) echo "Found the -a option" ;;
b) echo "Found the -b option, with parameter value $OPTARG" ;; # $OPTARG中存儲選項後參數
c) echo "Found the -c option" ;;
*) echo "Unknown option: $opt" ;;
esac
done
可以將選項和參數合在一起,中間不加空格;還可以將所有未定義參數統一輸出成問號?
四、 獲得用戶輸入
read命令可從標準輸入(鍵盤)或另一個文件中接收輸入,並保存到一個變量,下面來看其常用用法。
1. 基本讀取
最簡單的用法,-p會顯示指定的輸入提示符
#! /bin/bash
read -p "Input your name: " name
echo "Hello $name"
可以輸入多個參數
#! /bin/bash
read -p "Input your name and age: " name age
echo "Hello $name,age $age"
如果變量數>輸入參數,會從前往後分配,後面的變量爲空;如果變量數<輸入參數,多餘的參數會全存在最後一個變量
若不指定參數,read會將接收到的數據存入特殊變量REPLY中
#! /bin/bash
read -p "Input your name: "
echo "Hello $REPLY"
2. 超時設置 -t
如果用戶一直不輸入,read默認會一直等,-t選項可以設置定時器指定等待秒數,超時後read命令會返回非0退出狀態碼。
#! /bin/bash
if read -t 5 -p "Input your name: "
then
echo "Hello $REPLY"
else
echo #避免Timeout直接輸出在提示語句後面
echo "Timeout"
fi
3. 輸入指定字符數後自動退出 -n
read命令的 “-n數字” 選項可指定在用戶輸入指定字符數後自動退出,無需按回車。
#! /bin/bash
read -n1 -p "Please input a character: "
echo
echo "Your input is $REPLY"
4. 隱藏輸入 -s
有時用戶希望將輸入傳入腳本但又不在屏幕上顯示,典型情況就是輸密碼。read命令的-s選項就可以做到(實際也會顯示,只是read命令將其改爲了與屏幕底色相同)。
#! /bin/bash
read -s -p "Please input your password: "
echo
echo "Is your password really $REPLY"
5. 從文件中讀取
每次調用read命令會從文件中讀取一行文本,當文件中再沒有內容時,read會以非0狀態碼退出。最常見的方法是cat文件,將結果通過管道傳給通過while命令的read命令。
#! /bin/bash
# reading data from a file
count=1
cat breaktest.sh | while read line
do
echo "Line $count: $line"
count=$[ $count + 1 ]
done
echo "--- end of file ---"