shell腳本從入門到精通(初級)之入門篇


寫在開頭
本文是閱讀《Linux命令行與shell腳本編程大全》時的一些筆記,主要是shell腳本的一些基本語法,
還有很多細節和高級內容沒有寫到。
筆者也是shell script菜鳥,如有不當歡迎指正。
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 是一個數字
$# 傳遞給腳本或函數的參數個數。
$* 傳遞給腳本或函數的所有參數。
$@ 傳遞給腳本或函數的所有參數
$? 上個命令的退出狀態,或函數的返回值。
$$ 當前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: $@"
echo "Quoted Values: $*"
echo "PID $$"
echo "$?"

$@ 與 $* 的區別

$* 和 $@ 都表示傳遞給函數或腳本的所有參數,不被雙引號(" ")包含時,都以"$1" "$2" … "$n" 的形式輸出所有參數。
但是當它們被雙引號(" ")包含時,"$*" 會將所有的參數作為一個整體,以"$1 $2 … $n"的形式輸出所有參數;"$@" 會將各個參數分開,以"$1" "$2" … "$n" 的形式輸出所有參數。

#!/bin/bash
echo ‘$@:’
for i in $@;do
    echo $i
done
echo ‘"$@:"’
for i in "$@";do
    echo $i
done
echo ‘$*:’
for i in $*;do
    echo $i
done
echo ‘"$*:"’
for i in "$*";do
    echo $i
done
結果:
$@:
1
2
3
"$*":
1
2
3
$@:
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
root@localhost:/# ./getopts.sh -i apache2
install service apache2
root@localhost:/# ./getopts.sh -r
remove all service
root@localhost:/# ./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 {
     arr=$@
     echo "The received array is ${arr[*]}"
}
myarr=(1 2 3 4 5)
# 將該數組變量的值分解成單個的值,然后將這些值作為函數參數使用。
foo ${myarr[*]}

七、控制腳本

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 退出狀態碼越界


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM