1. 程式人生 > >shell指令碼入門(基本用法)

shell指令碼入門(基本用法)

一、變數

1. 環境變數

#!/bin/bash
# 全域性變數
echo "User Info:"
echo "user: $USER"
echo "UID : $EUID"
echo "home: $HOME"
echo “$HOSTNAME”

2. 使用者變數

變數命名規則:

  1. 由字母、數字和下劃線組成
  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

功能:

  1. 數值比較
  2. 字串比較
  3. 檔案比較

格式:

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"

五、輸出

顯示指令碼輸出的方法:

  1. 在顯示器上顯示
  2. 將輸出重定向到檔案
描述符 縮寫 描述
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.返回值

  1. 預設退出狀態碼
#!/bin/bash
function foo {
    echo "This is a func"
}
foo
echo "Exit status is $?"
  1. 使用return命令
#!/bin/bash
function foo {
    echo "Hello world"
    return 2
}
foo
echo "Exit status is $?"
 ./func.sh
Hello world
Exit status is 2
  1. 使用函式輸出
#!/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.變數

  1. 傳參
#!/bin/bash
function status {
    systemctl status $1
}
status sshd
  1. 區域性變數與全域性變數
#!/bin/bash
# 定義全域性變數
hostname="web"
function foo {
      str="hello"
      # 使用 local 定義區域性變數
      local  user="http"
      # 可以在函式內使用全域性變數
      echo "$hostname"
      echo "$user"
}
foo
# 在函式中定義的區域性變數不能在全域性使用
echo "$str $user"
  1. 陣列變數
    如果將陣列變數作為函式引數,函式只會取陣列變數的第一個值
#!/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.指令碼執行

  1. 指令碼執行
    bash file.sh

    chmod +x file.sh
    ./file.sh
  2. 後臺執行指令碼
    ./test.sh &
    nohub ./test.sh &

附:退出狀態

可以使用$?檢視上一個命令的退出狀態碼
狀態碼 | 含義
--- |---
0 | 命令成功結束
1 | 通用未知錯誤
2 | 誤用shell命令
126 | 命令不可執行
127 | 沒有找到命令
128+x | Linux訊號x的嚴重錯誤
130 | 命令通過Ctrl+C終止
255 | 退出狀態碼越界

---恢復內容結束---

# Shell 指令碼學習筆記