02 . Shell變量和邏輯判斷及循環使用


Shell變量

系統變量

在命令行提示符直接執行 env、set 查看系統或環境變量。env 顯示用戶環境變量,set 顯示 Shell預先定義好的變量以及用戶變量。可以通過 export 導出成用戶變量。

一些寫Shell腳本時常用的系統變量

$SHELL  默認 Shell
$HOME  當前用戶家目錄
$IFS  內部字段分隔符
$LANG  默認語言
$PATH  默認可執行程序路徑
$PWD  當前目錄
$UID  當前用戶 ID
$USER  當前用戶
$HISTSIZE  歷史命令大小,可通過 HISTTIMEFORMAT 變量設置命令執行時間
$RANDOM  隨機生成一個 0 至 32767 的整數
$HOSTNAME  主機名
普通變量與臨時環境變量

普通變量定義:VAR=value

臨時環境變量定義:export VAR=value

變量引用:$VAR

下面看下他們之間區別:

Shell 進程的環境變量作用域是 Shell 進程,當 export 導入到系統變量時,則作用域是 Shell 進程及其 Shell 子進程。

Shell 進程的環境變量作用域是 Shell 進程,當 export 導入到系統變量時,則作用域是 Shell 進程及其 Shell 子進程。

ps axjf 輸出的第一列是 PPID(父進程 ID),第二列是 PID(子進程 ID)當SSH 連接 Shell 時,當前終端 PPID(-bash)是 sshd 守護程序的 PID(root@pts/0),因此在當前終端下的所有進程的 PPID 都是-bash 的 PID,比如執行命令、運行腳本。

所以當在-bash 下設置的變量,只在-bash 進程下有效,而-bash 下的子進程 bash 是無效的,當export 后才有效。

進一步說明:再重新連接 SSH,去除上面定義的變量測試下所以在當前 shell 定義的變量一定要 export,否則在寫腳本時,會引用不到。

還需要注意的是退出終端后,所有用戶定義的變量都會清除。

在/etc/profile 下定義的變量就是這個原理.

位置變量

位置變量指的是函數或腳本后跟的第 n 個參數。

1−1−n,需要注意的是從第 10 個開始要用花括號調用,例如${10}

shift 可對位置變量控制,例如:

#!/bin/bash
echo "1: $1"
shift
echo "2: $2"
shift
echo "3: $3"

sh test.sh 1 2 3
1: 1
2: 3
3: 
# 每執行一次 shift 命令,位置變量個數就會減一,而變量值則提前一位。shift n,可設置向前移動n位。
特殊變量
$0  # 腳本自身名字
$?  # 返回上一條命令是否執行成功,0 為執行成功,非 0 則為執行失敗
$#  # 位置參數總數
$*  # 所有的位置參數被看做一個字符串
$@  # 每個位置參數被看做獨立的字符串
$$  # 當前進程 PID
$!  # 上一條運行后台進程的 PID
變量引用
賦值運算符 示例
= 變量賦值
+= 兩個變量相加
自定義變量與引用
a=123
echo $a
123

a+=456
echo $a
123456

# Shell 中所有變量引用使用$符,后跟變量名

# 有時個別特殊字符會影響正常使用,就需要使用${a},例如
[root@redis ~]# b=123
[root@redis ~]# echo $b
123
[root@redis ~]# echo ${b}
123
# 有時個別特殊字符會影響正常引用,那么需要使用${VAR}
[root@redis ~]# echo $b123

[root@redis ~]# echo ${b}123
123123


# 將命令結果作為變量值
[root@redis ~]# c=`echo 123`
[root@redis ~]# echo $c
123
[root@redis ~]# c=$(echo 123)
[root@redis ~]# echo $c
123

# 這里的反撇號等效於$(),都是用於執行 Shell 命令。

# 單引號和雙引號
[root@redis ~]# d=1
[root@redis ~]# d="1 2 $d"
[root@redis ~]# echo $d
1 2 1
[root@redis ~]# c=1
[root@redis ~]# c='1 2 $c'
[root@redis ~]# echo $c
1 2 $c
# 單引號是告訴 Shell 忽略特殊字符,而雙引號則解釋特殊符號原有的意義,比如$ 、 !。
Shell變量的輸入

Shell變量除了可以直接賦值或腳本傳參外,還可以使用read命令從標准輸入獲得,read為bash內置命令,可以通過help read查看幫助

語法格式

# read [參數] [變量名]

常用參數

# -p prompt: 設置提示信息
# -t timeout: 設置輸入等待的事件,單位默認為秒

read的基本讀入

如果不加-t read就會一直等待

# read后面的參數是一個變量
[root@youmen ~]# read -p 'please input you num:' num
please input you num:234
[root@youmen ~]# echo $num
234


# 設置超時事件為3秒
read -t 3 -p "please input you num:" num
please input you num:
# 過3秒鍾會腳本會自己執行結束

read在腳本中常用例子

[root@youmen ~]# sh test.sh 
please input you num: 1 2
1-2 =-1
1+2 =3
1*2 =2
1/2 =0
1**2 =1
1%2 =1
[root@youmen ~]# cat abc.sh 
#!/bin/bash
read -t 18 -p "please input you num:" a b
echo "$a-$b =$(( $a - $b ))"
echo "$a+$b =$(( $a + $b ))"
echo "$a*$b =$(( $a * $b ))"
echo "$a/$b =$(( $a / $b ))"
echo "$a**$b =$(( $a ** $b ))"
echo "$a%$b =$(( $a % $b ))"

# 利用echo 命令替代和read -p的功能
[root@youmen ~]# cat test.sh 
#!/bin/bash
echo -n "請輸入兩個數字:"
read a b 
echo "$a+$b =$(( $a + $b ))"
echo "$a*$b =$(( $a * $b ))"
echo "$a/$b =$(( $a / $b ))"
echo "$a**$b =$(( $a ** $b ))"
echo "$a%$b =$(( $a % $b ))"

[root@youmen ~]# bash test.sh 
請輸入兩個數字:2 3
2+3 =5
2*3 =6
2/3 =0
2**3 =8
2%3 =2

條件測試與比較

介紹

在bash的各種流程控制結構中通常要進行各種測試,然后根據測試結果執行不同的操作,有時也會通過與if等條件語句相結合,更方便的完成判斷

條件測試通常由如下3種語法形式

# 語法1:test<測試表達式>
# 語法2:[<測試表達式>]
# 語法3:[[<測試表達式>]]

# 說明
# 1.上述語法格式1和語法格式2的寫法是相等的。語法格式3為擴展的test命令。推薦使用語法格式2.

# 2.在[[]]中可以使用通配符進行模式匹配。&&、||、>、<等操作可以應用於[[]]中,但不能應用於[]中.

# 3.對於整數的關系運算,也可以使用Shell的算術運算符(())
test測試表達式
# 判斷是不是文件
[root@youmen ~]# test -f /etc/hosts
[root@youmen ~]# echo $?
0
[root@youmen ~]# test -f /etc/hostss
[root@youmen ~]# echo $?
1

# 判斷文件是否可以執行
[root@youmen ~]# test -x /usr/bin/ssh
[root@youmen ~]# echo $?
0
[root@youmen ~]# test -x /etc/hosts
[root@youmen ~]# echo $?
1

# 判斷是不是目錄
[root@youmen ~]# test -d /etc/
[root@youmen ~]# echo $?
0
[root@youmen ~]# test -d /etc/hosts
[root@youmen ~]# echo $?
1
[]中括號表達式
# 判斷是不是普通文件
[root@youmen ~]# [ -f /etc/hosts ]
[root@youmen ~]# echo $?
0
[root@youmen ~]# [ -f /etc/hostss ]
[root@youmen ~]# echo $?
1

# 判斷是否是目錄
[root@youmen ~]# [ -d /etc/hosts ]
[root@youmen ~]# echo $?
1
[root@youmen ~]# [ -d /etc/ ]
[root@youmen ~]# echo $?
0

# 判斷是否可被執行
[root@youmen ~]# [ -x /etc/hosts ]
[root@youmen ~]# echo $?
1
[root@youmen ~]# [ -x /usr/bin/ssh ]
[root@youmen ~]# echo $?
0
[[雙括號表達式]]
[root@youmen ~]# [[ -x /etc/hosts ]]
[root@youmen ~]# echo $?
1
[root@youmen ~]# [[ -x /usr/bin/ssh ]]
[root@youmen ~]# echo $?
0

# [[]] 和[]一樣
# 區別是可以在多括號里面添加多個判斷
# 例如判斷是不是目錄,並判斷下一個文件是不是可執行
[root@youmen ~]# [[ -d /etc/ && -x /usr/bin/ssh ]]
[root@youmen ~]# echo $?
0
[root@youmen ~]# [[ -d /etc/ && -x /usr/bin/sshdd ]]
[root@youmen ~]# echo $?
1

# &&只在雙括號里面有效,如果單括號里面需要使用-a,-o
文件測試表達式
操作符 說明 舉例

# -b file 檢測文件是否是塊設備文件,如果是,則返回 true。 [ -b $file ] 返回 false。

# -c file 檢測文件是否是字符設備文件,如果是,則返回 true。 [ -c $file ] 返回 false。

# -d file 檢測文件是否是目錄,如果是,則返回 true。 [ -d $file ] 返回 false。

# -f file 檢測文件是否是普通文件(既不是目錄,也不是設備文件),如果是,則返回 true。 [ -f $file ] 返回 true。 

# -g file 檢測文件是否設置了 SGID 位,如果是,則返回 true。 [ -g $file ] 返回 false。 

# -k file 檢測文件是否設置了粘着位(Sticky Bit),如果是,則返回 true。 [ -k $file ] 返回 false。 

# -p file 檢測文件是否是具名管道,如果是,則返回 true。 [ -p $file ] 返回 false。

# -u file 檢測文件是否設置了 SUID 位,如果是,則返回 true。 [ -u $file ] 返回 false。

# -r file 檢測文件是否可讀,如果是,則返回 true。 [ -r $file ] 返回 true。

# -w file 檢測文件是否可寫,如果是,則返回 true。 [ -w $file ] 返回 true。

# -x file 檢測文件是否可執行,如果是,則返回 true。 [ -x $file ] 返回 true。

# -s file 檢測文件是否為空(文件大小是否大於0),不為空返回 true。 [ -s $file ] 返回 true。

# -e file 檢測文件(包括目錄)是否存在,如果是,則返回 true。 [ -e $file ] 返回 true。

# 特別說明:這些操作符號對於[[]]、[]、test幾乎都是通用的,

字符串表達式

字符串測試操作符的作用有:比較兩個字符串是否相同、字符串的長度是否為零,字符串是否為NULL(注:bash區分零長度字符串和空字符串)等

常用字符串測試操作符 說明 -z “字符串” 若串長度為0則真,-z可以理解為zero -n ”字符串“ 若昂度不為0則真,-n 可以理解為no zero ”串1“ = ”串2“

若串1等於串2則真,可以使用”==“代替”=“

“串2” != “串2”

若串1不等於串2則真,不能用“!==“ 代替”!=“ 特別注意:

# 1. 以上表格中的字符串測試操作符號務必要用”“引起來。
# 2.比較符號兩端有空格

字符串測試操作符提示

# 1)-n 比較字符串長度是否不為零,如果不為零則為真,如:[ -n “$myvar” ]

# 2)-z 比較字符串長度是否等於零,如果等於零則為真,如:[ -z “$myvar” ]

# 特別注意
# 對於以上表格中的字符串測試操作符號,如[ -n “$myvar” ],要把字符串用“”引起來。

# 1、字符串或字符串變量比較都要加雙引號之后再比較。

# 2、字符串或字符串變量比較,比較符號兩端最好都有空格,可以參考系統腳本

# “=”比較兩個字符串是否相同,與“==”等價,如[ “$a” = “$b” ]其中$a這樣的變量最好用“”括起來,因為如果中間由空格,*等符號就可能出錯,更好的辦法就是[ “${a}” = “${b}” ]

# “!=” 比較兩個字符串是否相同,不同則為“是”

邏輯操作符

在[]和test中使用 在[[]]中使用 說明 -a && and與,兩端都為真,則真 -o || or或,兩端有一個為真則真 ! ! not非,相反則為真

# !中文意思是反:與一個邏輯值相關的邏輯值

# -a 中文意思是(and|&&):兩個邏輯值都為“真”,返回值才為“真”,反之為“假”

# -o 中文意思是或(or| ||):兩個邏輯值只要有一個為“真”,返回值就為“真”

# 邏輯操作運算規則
# -a和&& 的運算規則:只有兩端都是1才為真
# 要想使用&&注意雙括號

Shell流程控制

If

if 語句語法格式

if condition
then
    command1 
    command2
    ...
    commandN 
fi

# 寫成一行
if [ $(ps -ef | grep -c "ssh") -gt 1 ]; then echo "true"; fi
If else

if else語法格式

if condition
then
    command1 
    command2
    ...
    commandN
else
    command
fi
if else-if else

if else-if else語法格式

if condition1
then
    command1
elif condition2 
then 
    command2
else
    commandN
fi

實例

a=10
b=20
if [ $a == $b ]
then
   echo "a 等於 b"
elif [ $a -gt $b ]
then
   echo "a 大於 b"
elif [ $a -lt $b ]
then
   echo "a 小於 b"
else
   echo "沒有符合的條件"
fi

# a 小於 b

if else語句經常與test命令結合使用,如下所示

num1=$[2*3]
num2=$[1+5]
if test $[num1] -eq $[num2]
then
    echo '兩個數字相等!'
else
    echo '兩個數字不相等!'
fi

# 輸出結果
# 兩個數字相等!

循環

for

語法格式

for var in item1 item2 ... itemN
do
    command1
    command2
    ...
    commandN
done

# 寫成一行
for var in item1 item2 ... itemN; do command1; command2… done;

# 當變量值在列表里,for循環即執行一次所有命令,使用變量名獲取列表中的當前取值。
# 命令可為任何有效的shell命令和語句。in列表可以包含替換、字符串和文件名。
# in列表是可選的,如果不用它,for循環使用命令行的位置參數。
# 順序輸出當前列表中的數字

for loop in 1 2 3 4 5
do
    echo "The value is: $loop"
done

# 輸出
The value is: 1
The value is: 2
The value is: 3
The value is: 4
The value is: 5
  
# 順序輸出字符串中的字符
for str in 'This is a string'
do
    echo $str
done
# 輸出結果
This is a string

多種語法

# 類c語言
for ((i=1; i<=100; i ++))
do
	echo $i
done


# in使用
for i in {1..100}
do
	echo $i
done

# seq使用

for i in `seq 1 100`
do
	echo $i
don

While

while循環用於不斷執行一系列命令,也用於從輸入文件中讀取數據;命令通常為測試條件。其格式為:

while condition
do
    command
done

一下是一個基本的while循環,測試條件是,如果int小於等於5,那么條件返回真。int從0開始,每次循環處理時,int加1。運行上述腳本,返回數字1到5,然后終止。

#!/bin/bash
int=1
while(( $int<=5 ))
do
    echo $int
    let "int++"
done

# 輸出
1
2
3
4
5

# 以上實例使用了 Bash let 命令,它用於執行一個或多個表達式,變量計算中不需要加上 $ 來表示變量
# while循環可用於讀取鍵盤信息。下面的例子中,輸入信息被設置為變量FILM,按<Ctrl-D>結束循環

echo '按下 <CTRL-D> 退出'
echo -n '輸入你最喜歡的網站名: '
while read FILM
do
    echo "是的!$FILM 是一個好網站"
done

# 運行腳本,輸出類似下面
按下 <CTRL-D> 退出
輸入你最喜歡的網站名: youmeblog
是的!youmenblog 是一個好博客
無限循環

無限循環語法格式

while :
do
    command
done

# or
while true
do
    command
done

# or 
for (( ; ;))
until循環

until 循環執行一系列命令直至條件為 true 時停止。

until 循環與 while 循環在處理方式上剛好相反。

一般 while 循環優於 until 循環,但在某些時候—也只是極少數情況下,until 循環更加有用。

until 語法格式

until condition
do
    command
done

condition 一般為條件表達式,如果返回值為 false,則繼續執行循環體內的語句,否則跳出循環。

以下實例我們使用 until 命令來輸出 0 ~ 9 的數字:

#!/bin/bash

a=0

until [ ! $a -lt 10 ]
do
   echo $a
   a=`expr $a + 1`
done

# 運行結果
0
1
2
3
4
5
6
7
8
9
case

Shell case語句為多選擇語句。可以用case語句匹配一個值與一個模式,如果匹配成功,執行相匹配的命令。case語句格式如下:

case 值 in
模式1)
    command1
    command2
    ...
    commandN
    ;;
模式2)
    command1
    command2
    ...
    commandN
    ;;
esac

case工作方式如上所示。取值后面必須為單詞in,每一模式必須以右括號結束。取值可以為變量或常數。匹配發現取值符合某一模式后,其間所有命令開始執行直至 ;;。

取值將檢測匹配的每一個模式。一旦模式匹配,則執行完匹配模式相應命令后不再繼續其他模式。如果無一匹配模式,使用星號 * 捕獲該值,再執行后面的命令。

下面的腳本提示輸入1到4,與每一種模式進行匹配:

echo '輸入 1 到 4 之間的數字:'
echo '你輸入的數字為:'
read aNum
case $aNum in
    1)  echo '你選擇了 1'
    ;;
    2)  echo '你選擇了 2'
    ;;
    3)  echo '你選擇了 3'
    ;;
    4)  echo '你選擇了 4'
    ;;
    *)  echo '你沒有輸入 1 到 4 之間的數字'
    ;;
esac

# 輸入不同的內容,會有不同的結果,例如:
輸入 1 到 4 之間的數字:
你輸入的數字為:
3
你選擇了 3
break

break命令允許跳出所有循環(終止執行后面的所有循環)

下面的例子中,腳本進入死循環直至用戶輸入數字大於5。要跳出這個循環,返回到shell提示符下,需要使用break命令

#!/bin/bash
while :
do
    echo -n "輸入 1 到 5 之間的數字:"
    read aNum
    case $aNum in
        1|2|3|4|5) echo "你輸入的數字為 $aNum!"
        ;;
        *) echo "你輸入的數字不是 1 到 5 之間的! 游戲結束"
            break
        ;;
    esac
done

# 執行以上代碼,輸出結果為
輸入 1 到 5 之間的數字:3
你輸入的數字為 3!
輸入 1 到 5 之間的數字:7
你輸入的數字不是 1 到 5 之間的! 游戲結束
continue

continue命令與break命令類似,只有一點差別,它不會跳出所有循環,僅僅跳出當前循環。對上面的例子進行修改:

#!/bin/bash
while :
do
    echo -n "輸入 1 到 5 之間的數字: "
    read aNum
    case $aNum in
        1|2|3|4|5) echo "你輸入的數字為 $aNum!"
        ;;
        *) echo "你輸入的數字不是 1 到 5 之間的!"
            continue
            echo "游戲結束"
        ;;
    esac
done
Case..esac

case ... esac 與其他語言中的 switch ... case 語句類似,是一種多分枝選擇結構,每個 case 分支用右圓括號開始,用兩個分號 ;; 表示 break,即執行結束,跳出整個 case ... esac 語句,esac(就是 case 反過來)作為結束標記。

case ... esac 語法格式如下

case 值 in
模式1)
    command1
    command2
    command3
    ;;
模式2)
    command1
    command2
    command3
    ;;
*)
    command1
    command2
    command3
    ;;
esac

# case后為取值,值可以為變量或常數
# 值后為關鍵字 in,接下來是匹配的各種模式,每一模式最后必須以右括號結束,模式支持正則表達式。

#!/bin/sh

site="runoob"

case "$site" in
   "runoob") echo "youmen博客"
   ;;
   "google") echo "Google 搜索"
   ;;
   "taobao") echo "淘寶網"
   ;;
esac


免責聲明!

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



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