我們今天接着學習shell編程!
首先接着介紹shell腳本中的非常重要的一種變量:位置變量
位置變量 : 在腳本中調用通過命令行參數傳遞給腳本的參數。
$1 , $2 , … : 對應調用第1、第2…等參數
$0 : 命令本身
$* : 傳遞給腳本的所有參數
$@ : 傳遞給腳本的所有參數(與$*是有區別的)
$# : 傳遞給腳本的參數個數
示例:
我們寫一個腳本test.sh來測試一下:
#!/bin/bash
#
echo $0
echo $2
echo "\$* : $*"
echo "\$@ : $@"
echo "\$# : $#"
執行命令,結果如下:
[jeffrey@localhost ~]$ chmod +x test.sh
[jeffrey@localhost ~]$ ./test.sh Tom Jerry Cherry
./test.sh
Jerry
$* : Tom Jerry Cherry
$@ : Tom Jerry Cherry
$# : 3
shift : 參數左移
用法:
在shell腳本中,用於將參數踢出:
shift :踢出一個參數,即第二個參數變成第一個,第三個參數變成第二個;
shift # :踢出#個參數;
示例:
我們輸入4個參數,分別爲Tom,Jerry,Cherry,Baby,首先打印出第一個參數,即Tom;然後踢出第一個參數,此時第二個參數Jerry變成第一個參數,再次打印參數1,顯示的便是Jerry…
#!/bin/bash
#
echo $1
shift
echo $1
shift 2
echo $1
echo "\$* : $*"
echo "\$@ : $@"
echo "\$# : $#"
[jeffrey@localhost ~]$ ./test.sh Tom Jerry Cherry Baby
Tom
Jerry
Baby
$* : Baby
$@ : Baby
$# : 1
算術運算
執行算術運算操作有如下四種方式:
(1)# let var = EXPRESSION 運算結果不直接打印出來;
(2)# var = $[ EXPRESSION ] 運算結果會直接打印出來;
(3)# var = $(( EXPRESSION )) 運算結果直接打印出來;
(4)# var = $(expr EXPRESSION) 算術表達式以空格隔開,結果不直接打印出來,且*需要轉義;
示例1:
[jeffrey@localhost ~]$ num1=4
[jeffrey@localhost ~]$ num2=8
[jeffrey@localhost ~]$ let sum=$num1+$num2
[jeffrey@localhost ~]$ echo $sum
12
示例2:
[jeffrey@localhost ~]$ var1=$[$num1+$num2]
[jeffrey@localhost ~]$ echo $var1
12
示例3:
[jeffrey@localhost ~]$ var2=$(($num1+num2))
[jeffrey@localhost ~]$ echo $var2
12
示例4:注意,表達式變量與運算符要以空格隔開;
[jeffrey@localhost ~]$ var3=$(expr $num1 + $num2)
[jeffrey@localhost ~]$ echo $var3
12
- bash內建的隨機數生成器:$RANDOM
示例:
生產60以內的隨機數
[jeffrey@localhost ~]$ VAR=$[$RANDOM%60]
[jeffrey@localhost ~]$ echo $VAR
18
[jeffrey@localhost ~]$ VAR=$[$RANDOM%60]
[jeffrey@localhost ~]$ echo $VAR
48
[jeffrey@localhost ~]$ VAR=$(($RANDOM%60))
[jeffrey@localhost ~]$ echo $VAR
6
[jeffrey@localhost ~]$ let VAR=$RANDOM%60
[jeffrey@localhost ~]$ echo $VAR
49
[jeffrey@localhost ~]$ VAR=$(expr $RANDOM % 60)
[jeffrey@localhost ~]$ echo $VAR
37
- 增強型賦值
+=,-=,*=,/=,%=,++,–
示例:
[jeffrey@localhost ~]$ let var=13
[jeffrey@localhost ~]$ echo $var
13
[jeffrey@localhost ~]$ let var-=3
[jeffrey@localhost ~]$ echo $var
10
[jeffrey@localhost ~]$ let var*=2
[jeffrey@localhost ~]$ echo $var
20
[jeffrey@localhost ~]$ let var/=4
[jeffrey@localhost ~]$ echo $var
5
[jeffrey@localhost ~]$ let var%=3
[jeffrey@localhost ~]$ echo $var
2
[jeffrey@localhost ~]$ let var++
[jeffrey@localhost ~]$ echo $var
3
[jeffrey@localhost ~]$ let var--
[jeffrey@localhost ~]$ echo $var
2
條件測試:判斷條件是否滿足;由測試機制來實現;
用法
專用的測試表達式需要由測試命令輔助完成測試過程,測試命令如下:
~]# test EXPRESSION
~]# [ EXPRESSION ]
~]# [[ EXPRESSION ]]
注:EXPRESSION前後必須有空格,並且[ ]或[[ ]]中的變量和運算符要以空格分隔;
bash的測試類型: 數值測試 、字符串測試、文件測試。
數值測試:
- -gt 大於
- -ge 大於等於
- -eq 等於
- -ne 不等於
- -lt 小於
- le 小於等於
示例1:
[jeffrey@localhost ~]$ test 1>3
[jeffrey@localhost ~]$ echo $?
1
示例2:
[jeffrey@localhost ~]$ [ 100 -eq 100 ]
[jeffrey@localhost ~]$ echo $?
0
示例3:
[jeffrey@localhost ~]$ [[ 100 -ne 100 ]]
[jeffrey@localhost ~]$ echo $?
1
字符串測試:用於字符串比較時的操作數應該加引號
- ==或者= 相等
- > 大於
- < 小於
- != 不等於
- =~ 左側是否能被右側的PATTERN匹配,一般用於[[ ]]中;
- -z “STRING” 測試字符串是否爲空;不空爲真、空爲假;
- -n “STRING” 測試字符串是否不爲空;不空爲真、空爲假;
示例1:
[jeffrey@localhost ~]$ name=jeffrey
[jeffrey@localhost ~]$ echo $name
jeffrey
/*下面錯誤的原因是[和-z之間沒以空格隔開*/
[jeffrey@localhost ~]$ [-z "$name"]
bash: [-z: command not found...
jeffrey@localhost ~]$ [ -z "$name" ]
[jeffrey@localhost ~]$ echo $?
1
示例2:
[jeffrey@localhost ~]$ myname=jeffrey
[jeffrey@localhost ~]$ [ -n "$myname" ]
[jeffrey@localhost ~]$ echo $?
0
示例3:
[jeffrey@localhost ~]$ [ "$name" = "$myname" ]
[jeffrey@localhost ~]$ echo $?
0
示例4:
jeffrey@localhost ~]$ [[ "$name" =~ ^m ]]
[jeffrey@localhost ~]$ echo $?
1
[jeffrey@localhost ~]$ [[ "$name" =~ ^t ]]
[jeffrey@localhost ~]$ echo $?
1
文件測試
(1)文件存在性測試
- -a FILE 及 -e FILE 測試文件是否存在;
(2)存在性及類別測試
- -b FILE 文件是否存在且爲快文件
- -c FILE 文件是否存在且爲字符設備文件
- -d FILE 文件是否存在且爲目錄文件
- -f FILE 文件是否存在且爲普通文件
- -p FILE 文件是否存在且爲命名管道文件
- -S FILE 文件是否存在切勿套接字文件
- -h FILE 或 -L FILE 文件是否村咋且爲符號鏈接文件
(3)文件權限測試
- -r FILE 文件是否存在且可讀(對於當前用戶而言)
- -w FILE 文件是否存在且可寫
- -x FILE 文件是否存在且可執行
(4)文件特殊權限測試
- -g FILE 文件是否存在且擁有sgid權限
- -u FILE 文件是否存在且擁有suid權限
- -k FILE 文件是否存在且擁有sticky權限
(5)文件大小測試
- -s FILE 文件是否存在且非空
(6)文件是否打開測試
- -t fd fd表示文件描述符是否已經打開且與某終端相關
(7)其他測試
- -N FILE 文件自動上一次被讀取之後是否被修改過
- -O FILE 當前有效用戶是否爲文件屬主
- -G FILE 當前有效用戶是否爲文件屬組
(8)雙目測試
- FILE1 -ef FILE2 測試FILE1和FILE2是否指向同一設備上的相同inode
- FILE1 -nt FILE2 測試FILE1是否新於FILE2
- FILE1 -ot FILE2 測試FILE1是否舊於FILE2
基於以上幾種測試類型,我們將其組合起來進行組合測試:
組合測試
在進行組合測試時,我們需要進行邏輯的運算,即與、或、非,與之前說過的條件測試命令結合起來,有以下兩種形式;
形式1:
- && 與
- || 或
- !非
形式2:
- -o 與
- -a 或
- !非
那麼,我們的組合測試方式也相應地有兩種方式;
方式1:
[ EXPRESSION1 ] && [ EXPRESSION2 ]
[ EXPRESSION1 ] | | [ EXPRESSION2 ]
! [ EXPRESSION ] 或 [ ! EXPRESSION ]
方式2:
[ EXPRESSION1 -a EXPRESSION2 ]
[ EXPRESSION1 -a EXPRESSION2 ]
! [ EXPRESSION ] 或 [ ! EXPRESSION ]
我們常用的測試命令爲[ ],當然也可以是其他測試命令;
我們示例說明:
首先,我們查看/usr/bin/ls和/work的詳細信息;
/usr/bin/ls爲普通文件,屬主權限爲可讀可寫可執行;
/work爲目錄文件,屬主權限爲可讀可寫可執行;
[jeffrey@localhost ~]$ ls -l /usr/bin/ls && ls -l -d /work
-rwxr-xr-x. 1 root root 117672 Apr 10 21:35 /usr/bin/ls
drwxr-xr-t. 4 root root 51 Sep 10 04:17 /work
1,我們測試“/usr/bin/ls存在 且 /work要對於當前用戶root可讀”,結果應爲正確;
法一:
[root@localhost jeffrey]# [ -e /usr/bin/ls ] && [ -r /work ]
[root@localhost jeffrey]# echo $?
0
法二:
[root@localhost jeffrey]# [ -e /usr/bin/ls -a -r /work ]
[root@localhost jeffrey]# echo $?
0
2,測試“/usr/bin/ls是目錄 且 /work對於當前用戶root可讀”,其結果應爲錯誤;
法一:
[root@localhost jeffrey]# [ -d /usr/bin/ls ] && [ -r /work ]
[root@localhost jeffrey]# echo $?
1
法二:
[root@localhost jeffrey]# [ -d /usr/bin/ls -a -r /work ]
[root@localhost jeffrey]# echo $?
1
3,測試“/usr/bin/ls是目錄 或 /work對於當前用戶root可讀”,其結果應爲正確;
法一:
root@localhost jeffrey]# [ -d /usr/bin/ls ] || [ -r /work ]
[root@localhost jeffrey]# echo $?
0
法二:
[root@localhost jeffrey]# [ -d /usr/bin/ls -o -r /work ]
[root@localhost jeffrey]# echo $?
0
bash自定義退出狀態碼
bash可以自定義退出狀態碼:exit n
若腳本中一旦遇到exit命令,腳本會立即終止,終止退出狀態取決於exit命令後面的數字;如果未給腳本指定退出狀態碼,整個腳本的退出狀態碼取決於腳本中執行的最後一條命令的狀態碼。
今天的練習:
1,計算系統上/etc/passwd上第10個用戶和第20個用戶的ID之和;
腳本sumid.sh內容如下:
#!/bin/bash
#
id1=$(head -10 /etc/passwd | tail -1 | cut -d: -f3)
id2=$(head -20 /etc/passwd | tail -1 | cut -d: -f3)
sum_ID=$[$id1+$id2]
echo "The sum of No.10 id and No.20 id is $sum_ID"
執行結果如下:
[jeffrey@localhost ~]$ chmod +x sumid.sh
[jeffrey@localhost ~]$ ./sumid.sh
The sum of No.10 id and No.20 id is 70
2,計算/etc/rc.d/rc.sysinit以及/etc/rc.d傳遞兩個文件路徑作爲參數給腳本,計算文件的空白行數之和;
腳本blankline.sh內容如下:
#!/bin/bash
#
line1=$(grep "^[[:space:]]*$" $1 | wc -l)
line2=$(grep "^[[:space:]]*$" $2 | wc -l)
sum=$[ $line1 + $line2 ]
echo "blank lines all is $sum"
執行結果:
[root@localhost jeffrey]# ./blankline.sh /etc/profile /etc/bashrc
blank lines all is 18
3,統計/etc,/var,/usr共有多少個子目錄和文件;
腳本count.sh內容:
#!/bin/bash
#
num1=$(ls -l /etc | wc -l)
num2=$(ls -l /var | wc -l)
num3=$(ls -l /usr | wc -l)
num=$[$num1+$num2+$num3]
echo "file number is $num"
執行結果如下:
[root@localhost jeffrey]# chmod +x count.sh
[root@localhost jeffrey]# ./count.sh
file number is 333
4,寫一個腳本,接受一個文件路徑作爲參數,若參數行小於1,則提示用戶“至少給出一個參數”,並立即退出;否則,顯示第一個參數所指向的文件中的空白行數;
腳本test.sh內容:
#!/bin/bash
#
[ "$#" -lt 1 ] && echo "至少應輸入一個參數" && exit 125
line=$(grep "^[[:space:]]*$" $1 | wc -l)
echo "$line"
執行結果:
[root@localhost jeffrey]# chmod +x test.sh
[root@localhost jeffrey]# ./test.sh
至少應輸入一個參數
[root@localhost jeffrey]# ./test.sh /etc/profile
11