shell指令碼入門(基本用法)
一、變數
1. 環境變數
#!/bin/bash
# 全域性變數
echo "User Info:"
echo "user: $USER"
echo "UID : $EUID"
echo "home: $HOME"
echo “$HOSTNAME”
2. 使用者變數
變數命名規則:
- 由字母、數字和下劃線組成
- 大小寫敏感
#!/bin/bash
# 使用者變數
var1=100
var2=hello
var3="hello world"
echo "$var1 $var2 $var3"
3. 特殊變數
變數 | 含義 |
---|---|
$0 | 當前指令碼的檔名 |
$n | 傳遞給指令碼或函式的引數。n 是一個數字 |
$# | 傳遞給指令碼或函式的引數個數。 |
$* | 傳遞給指令碼或函式的所有引數。 |
[email protected] | 傳遞給指令碼或函式的所有引數 |
$? | 上個命令的退出狀態,或函式的返回值。 |
$$ | 當前Shell程序ID。對於 Shell 指令碼,就是這些指令碼所在的程序ID。 |
#!/bin/bash
echo "Total Number of Parameters : $#"
echo "File Name: $0"
echo "First Parameter : $1"
echo "First Parameter : $2"
echo "Quoted Values: [email protected]"
echo "Quoted Values: $*"
echo "PID $$"
echo "$?"
[email protected] 與 $* 的區別
$* 和 [email protected] 都表示傳遞給函式或指令碼的所有引數,不被雙引號(" ")包含時,都以"$1" "$2" … "$n" 的形式輸出所有引數。
但是當它們被雙引號(" ")包含時,"$*" 會將所有的引數作為一個整體,以"$1 $2 … $n"的形式輸出所有引數;"[email protected]" 會將各個引數分開,以"$1" "$2" … "$n" 的形式輸出所有引數。
#!/bin/bash
echo ‘[email protected]:’
for i in [email protected];do
echo $i
done
echo ‘"[email protected]:"’
for i in "[email protected]";do
echo $i
done
echo ‘$*:’
for i in $*;do
echo $i
done
echo ‘"$*:"’
for i in "$*";do
echo $i
done
結果:
[email protected]:
1
2
3
"$*":
1
2
3
[email protected]:
1
2
3
"$*":
1 2 3
4. ``與$()
把命令的執行結果賦給變數的兩種方式
#!/bin/bash
time=`date +%y%m%d`
time=$(date +%y%m%d)
二、數學計算
1. expr
#!/bin/bash
# 注意變數和=之間不能有空格,expr 和 = 之間要有一個空格
var= expr 1 + 2
echo $var
expr 及其難用,一般不用
2. [] 與 (())
#!/bin/bash
#
var=$[ 1 + 2 ]
var=$(( 3 + 4 ))
3. bc
上述兩種只能計算整數,對於浮點數需要使用bc
在指令碼中使用bc的格式:
variable=`echo "option; expression" |bc`
#!/bin/bash
var=`echo "scale=2;5/3" | bc`
echo $var
三、邏輯控制
1. if
1.1 if-then
格式:
if command
then
command
fi
例:
#!/bin/bash
if date
then
echo "command is succeed"
fi
1.2 if-then-else
格式:
if command
then
command
else
command
fi
例:
#!/bin/bash
# 查詢系統中是否存在httpd使用者
if grep httpd /etc/passwd
then
echo "httpd is exist"
else
echo "httpd not find"
fi
1.3 if巢狀
格式:
if command
then
command
elif command
command
else
command
fi
2. test
功能:
- 數值比較
- 字串比較
- 檔案比較
格式:
test condition
或
[ command ] -- 更常用
2.1 數值比較
比較 | 描述 |
---|---|
-eq | 等於 |
-ge | 大於等於 |
-gt | 大於 |
-le | 小於等於 |
-lt | 小於 |
-ne | 不等於 |
例:
#!/bin/bash
date
if [ $? -eq 0 ];then
echo "command is succeed"
fi
# 或
if test date;then
echo "command is succeed"
fi
2.2 字串比較
比較 | 描述 | 例 |
---|---|---|
str1 = str2 | 字串是否相同 | |
str1 != str2 | 字串是否不同 | |
str1 < str2 | str1是否比str2小 | |
str1 > str2 | str1是否比str2大 | [ b \> a ] && echo "true" (注意>需要轉義) |
-n str | 字串長度非0為真 | [ -n "str" ] && echo "str is not null" |
-z str | 字串長度為0為真 | [ -z "" ] && echo "str is null" |
2.3 檔案比較
比較 | 描述 | 例 |
---|---|---|
-d file | 檢查file是否存在並是一個目錄 | [ -d /data ] && echo "exist" |
-f file | 檢查file是否存在並是一個目錄 | |
-e file | 檢查file是否存在 | |
-r file | 檢查file是否存在並可讀 | |
-s file | 檢查file是否存在並非空 | |
-w file | 檢查file是否存在並可寫 | |
-x file | 檢查file是否存在並可執行 | |
-O file | 檢查file是否存在並屬當前使用者所有 | |
-G file | 檢查file是否存在並且預設組與當前使用者相同 | |
file1 -nt file2 | file1是否比file2新 | |
file1 -ot file2 | file1是否比file2舊 |
2.4 符合條件
[ condition1 ] && [ condition2 ]
[ condition1 ] || [ condition2 ]
3. case
格式:
case variable in
pattern1 | pattern2) command1;;
pattern3) command2;;
*) default command;;
esca
例:
#!/bin/bash
read -p "input something: " var
case $var in
[0-9])
echo "number";;
[a-z])
echo "character";;
*)
echo "other";;
esac
4. for
4.1 bash中的for
格式:
for var in list
do
command
done
例1:檢視服務狀態
#!/bin/bash
for service in apache2 mysqld zabbix-server zabbix-agent
do
status=$(systemctl status mysql | awk '/Active/ {print $2,$3}')
echo $service $status
done
例2:使用萬用字元
#!/bin/bash
# 注意在$file上加“”,否則如果出現帶空格的目錄名,指令碼會出錯
for file in /tmp/*
do
if [ -d "$file" ]
then
echo "$file" is a directory
elif [ -f "$file" ]
then
echo "$file" is a file
fi
done
4.2 C 語言風格的for
例:
#!/bin/bash
for (( i=1; i<=10; i++ ))
do
echo $i
done
#!/bin/bash
# 單變數
for (( i=1; i<=10; i++ ))
do
echo $i
done
# 多變數
for (( i=1,j=10; i<=10; i++,j-- ))
do
echo $i $j
done
5. while
例:檢測站點狀態
#!/bin/bash
urls="
https://www.baidu.com
https://www.taobao.com
https://www.jd.com/abc
https://www.12306.cn/index/
192.168.1.111
"
for url in $urls;do
count=0
while [ $count -lt 3 ];do
STATUS=$(curl -I -m 10 -o /dev/null -s -w %{http_code} $url)
if [ $STATUS -eq 200 ];then
echo "$url OK"
break 1
fi
count=$(($count+1))
done
if [ $count -eq 3 ];then
echo "$url Error"
fi
done
6. until
#!/bin/bash
var=10
until [ $var -eq 0 ];do
var=$[$var-2]
echo $var
done
7. 控制迴圈
7.1 break
#!/bin/bash
# break 跳出當前迴圈
# break n 跳出n層迴圈
for (( i=0; i<10; i++ ));do
if [ $i -eq 5 ];then
break
fi
echo $i
done
7.2 continue
四、輸入
1. 命令列引數
例1:
#!/bin/bash
echo $1+$2=$[$1+$2]
./add.sh 3 4
3+4=7
例2:shift
#!/bin/bash
# 把變數的位置向左移
while [ -n "$1" ];do
echo $1
shift
done
2.getopts
格式:getopts optstring variable
optstring: 選項字母,如果字母要求有引數就加一個:,要去掉錯誤訊息的話可以在optstring前加一個:
variable:儲存當前引數
#!/bin/bash
# getopts的用法
# opt 會儲存輸入的引數,如 r i
# OPTARG儲存引數值
# 引數需要一個值就在引數後面加一個: 如i:
while getopts ri: opt
do
case "$opt" in
i) echo "install service $OPTARG";;
r) echo "remove all service";;
*) echo "Unknown option: $opt";;
esac
done
[email protected]:/# ./getopts.sh -i apache2
install service apache2
[email protected]:/# ./getopts.sh -r
remove all service
[email protected]:/# ./getopts.sh -a
./getopts.sh: illegal option -- a
Unknown option: ?
3. 獲得使用者輸入 read
3.1 普通用法
#!/bin/bash
read name
echo $name
3.2 指定提示符
#!/bin/bash
read -p "Enter your name: " name
echo "Hello $name "
3.3 指定超時時間
#!/bin/bash
if read -t 5 -p "Enter your name: " name
then
echo "Hello $name"
else
echo "TIME OUT"
fi
3.4 隱藏資料
#!/bin/bash
read -s -p "Enter passwd: " passwd
echo "$passwd"
3.5 限制輸入長度
#!/bin/bash
read -n1 -p "Do you want continue[Y/N]?" answer
echo
echo "$answer"
五、輸出
顯示指令碼輸出的方法:
- 在顯示器上顯示
- 將輸出重定向到檔案
描述符 | 縮寫 | 描述 |
---|---|---|
0 | STDIN | 標準輸入 |
1 | STDOUT | 標準輸出 |
2 | STDERR | 標準錯誤 |
1. 在指令碼中重定向
1. 臨時重定向
使用場景:在指令碼中生成錯誤訊息
#!/bin/bash
echo "This is an error message" >&2
echo "This is normal output"
預設情況下Linux 會將STDERR定向到STDOUT
$./error.sh
This is an error message
This is normal output
在執行指令碼的時候重定向STDERR,ERR文字就會被重定向
$ ./error.sh 2> error.log
This is normal output
$ cat error.log
This is an error message
2. 永久重定向
用exec命令告訴shell在執行指令碼期間重定向某個特定檔案描述符
#!/bin/bash
exec 2>errout
echo "This is error"
exec 1>testout
echo "testout"
echo "testout to errout" >&2
$ ./test.sh
This is error
$ cat errout
testout to errout
$ cat testout
testout
2. 記錄訊息
tee : 將輸出一邊傳送到顯示器一邊傳送到日誌檔案
tee 預設會覆蓋原來的檔案,可以使用-a追加
$ date | tee -a date.txt
Fri Nov 23 11:03:15 CST 2018
$ cat date.txt
Fri Nov 23 11:03:07 CST 2018
Fri Nov 23 11:03:15 CST 2018
六、函式
1.基本函式
#!/bin/bash
# 定義方式1
function foo {
echo "This is a func"
}
# 定義方式2
bar() {
echo "This is another func"
}
# 函式的呼叫
foo
bar
$ ./func.sh
This is a func
This is another func
2.返回值
- 預設退出狀態碼
#!/bin/bash
function foo {
echo "This is a func"
}
foo
echo "Exit status is $?"
- 使用return命令
#!/bin/bash
function foo {
echo "Hello world"
return 2
}
foo
echo "Exit status is $?"
./func.sh
Hello world
Exit status is 2
- 使用函式輸出
#!/bin/bash
function foo {
echo "Hello world"
}
foo
# 把函式的輸出賦值給變數
result=`foo`
echo "Exit status is $result"
$./func.sh
Hello world
Exit status is Hello world
3.變數
- 傳參
#!/bin/bash
function status {
systemctl status $1
}
status sshd
- 區域性變數與全域性變數
#!/bin/bash
# 定義全域性變數
hostname="web"
function foo {
str="hello"
# 使用 local 定義區域性變數
local user="http"
# 可以在函式內使用全域性變數
echo "$hostname"
echo "$user"
}
foo
# 在函式中定義的區域性變數不能在全域性使用
echo "$str $user"
- 陣列變數
如果將陣列變數作為函式引數,函式只會取陣列變數的第一個值
#!/bin/bash
function foo {
arr=$1
echo "The received array is ${arr[*]}"
}
myarr=(1 2 3 4 5)
foo $myarr
解決方法
#!/bin/bash
function foo {
[email protected]
echo "The received array is ${arr[*]}"
}
myarr=(1 2 3 4 5)
# 將該陣列變數的值分解成單個的值,然後將這些值作為函式引數使用。
foo ${myarr[*]}
4.
七、控制指令碼
1.處理訊號
1.1檢視Linux訊號
kill -l
1) SIGHUP 2) SIGINT 3) SIGQUIT 4) SIGILL 5) SIGTRAP
6) SIGABRT 7) SIGBUS 8) SIGFPE 9) SIGKILL 10) SIGUSR1
11) SIGSEGV 12) SIGUSR2 13) SIGPIPE 14) SIGALRM 15) SIGTERM
16) SIGSTKFLT 17) SIGCHLD 18) SIGCONT 19) SIGSTOP 20) SIGTSTP
21) SIGTTIN 22) SIGTTOU 23) SIGURG 24) SIGXCPU 25) SIGXFSZ
26) SIGVTALRM 27) SIGPROF 28) SIGWINCH 29) SIGIO 30) SIGPWR
31) SIGSYS 34) SIGRTMIN 35) SIGRTMIN+1 36) SIGRTMIN+2 37) SIGRTMIN+3
38) SIGRTMIN+4 39) SIGRTMIN+5 40) SIGRTMIN+6 41) SIGRTMIN+7 42) SIGRTMIN+8
43) SIGRTMIN+9 44) SIGRTMIN+10 45) SIGRTMIN+11 46) SIGRTMIN+12 47) SIGRTMIN+13
48) SIGRTMIN+14 49) SIGRTMIN+15 50) SIGRTMAX-14 51) SIGRTMAX-13 52) SIGRTMAX-12
53) SIGRTMAX-11 54) SIGRTMAX-10 55) SIGRTMAX-9 56) SIGRTMAX-8 57) SIGRTMAX-7
58) SIGRTMAX-6 59) SIGRTMAX-5 60) SIGRTMAX-4 61) SIGRTMAX-3 62) SIGRTMAX-2
63) SIGRTMAX-1 64) SIGRTMAX
在Linux程式設計時會遇到的最常見的Linux系統訊號
信 號 | 值 | 描 述 | 觸發 |
---|---|---|---|
1 | SIGHUP | 掛起程序 | |
2 | SIGINT | 終止程序 | Ctrl + C |
3 | SIGQUIT | 停止程序 | |
9 | SIGKILL | 無條件終止程序 | |
15 | SIGTERM | 儘可能終止程序 | |
17 | SIGSTOP | 無條件停止程序,但不是終止程序 | |
18 | SIGTSTP | 停止或暫停程序,但不終止程序 | Ctrl+Z |
19 | SIGCONT | 繼續執行停止的程序 |
1.2 捕捉訊號
格式:trap command signals
例
#!/bin/bash
trap "echo 'You Enter Ctrl + C'" SIGINT
for (( i=0; i<10; i++ ));do
echo $i
sleep 1
done
# ./signal.sh
0
1
^CYou Enter Ctrl + C
2
^CYou Enter Ctrl + C
2.指令碼執行
- 指令碼執行
bash file.sh
或
chmod +x file.sh
./file.sh - 後臺執行指令碼
./test.sh &
nohub ./test.sh &
附:退出狀態
可以使用$?檢視上一個命令的退出狀態碼
狀態碼 | 含義
--- |---
0 | 命令成功結束
1 | 通用未知錯誤
2 | 誤用shell命令
126 | 命令不可執行
127 | 沒有找到命令
128+x | Linux訊號x的嚴重錯誤
130 | 命令通過Ctrl+C終止
255 | 退出狀態碼越界
---恢復內容結束---
# Shell 指令碼學習筆記