shell編程之步步爲營(2):位置變量、shift、算術運算

我們今天接着學習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
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章