shell變數與運算
shell變數與運算
變數存在於記憶體中。假設變數str,設定或修改變數屬性時,不帶$號,只有引用變數的值
時才使用$號。也就是說在記憶體中,標記變數的變數名稱是str,而不是$str。
變數資料的儲存方式本身是有型別之分的,分為資料(整數、浮點型)和字元,在java等一些語言中,需要提前宣告變數是哪種型別。但是,在bash中變數比較寬鬆,不需要這麼做。
即,變數可以這麼分為:
- 強型別:變數不經過強制轉換,它永遠是這個資料型別,不允許隱式的型別轉換。一般定義變數時必須指定型別、參與運算必須符合型別要求;呼叫未宣告變數會產生錯誤。如java,c#
- 弱型別:語言的執行時會隱式做資料型別轉換。無須指定型別,預設均為字元型;參與運算會自動進行隱式型別轉換;變數無須事先定義可直接呼叫。
如:bash 不支援浮點數,php
變數命名法則:
1、不能使程式中的保留字:例如if, for
2、只能使用數字、字母及下劃線,且不能以數字開頭
3、見名知義
4、統一命名規則:駝峰命名法
駝峰命名法:將變數名首字母大寫,可以全部單詞的首字母大寫,也可以部分單詞的首字母大寫,方便識別。如:StudentName。
一、變數型別
1.1 區域性變數
生效範圍為當前shell程序;對當前shell之外的其它shell程序,包括當前shell的子shell程序均無效。
檢視程序編號:
echo $$ # 當前程序的程序編號 echo $PPID #父程序的程序編號 也可以通過 pstree -p # 檢視父子程序樹
如:NAME=songtai,這個變數只對當前的shell有用,子shell或父shell無法使用。退出當前shell用exit
命令
1、變數賦值:name=‘value’ 。
注意:注意等號左右沒有空格。如果有空格就是進行比較運算子的比較運算了。要想保留空格作為一個整體字串,用“”括起來。如:STR=“test space”。
注意:變數賦值也可以直接應用變數或命令:
1.直接引用字串:name=“root"
2.變數:name="$USER"
3.命令:name=`COMMAND` 或 name=$(COMMAND)
2、變數引用::${name} 或$name
如:
[[email protected] ~]#NAME="hello world"
[[email protected] ~]#echo "we will say $NAME"
we will say hello world
3、釋放變數:unset name
,注意變數名前不加字首$。
一般賦值完一個變數後,如果後邊不在使用該變數的話,直接釋放該變數。
4、檢視所有的變數:不接任何引數的set或者declare命令,輸出結果中包含了普通變數和環境變數。
5、臨時將普通變數升級為環境(全域性)變數: export name 或者賦值時 export name="value" ,這樣$name就可以在當前shell和子shell中使用,但是退出指令碼或者重新登入shell都會取消export效果。
6、定義只讀變數: readonly name 。這時將無法修改變數值也無法unset變數,只有重新登入shell才能繼續使用只讀變數。
1.2環境變數(全域性變數)
生效範圍為當前shell程序及其子程序。常用大寫字母
env
export
printenv
可以檢視當前使用者的環境變數。
常見的環境變數:HOSTNAME、SHELL、HISTSIZE、USER、PATH、PWD、LANG、HOME、LOGNAME。
變數宣告、賦值:
export name=VALUE
declare -x name=VALUE
注意:區域性變數通過export升級為全域性變數,並且對子shell產生影響,但是對父shell不產生影響,父shell仍是原來的賦值。
set
檢視全部變數,包括區域性變數、全域性變數。
1.3只讀變數
只能宣告,但不能修改和刪除
宣告只讀變數:
- readonly name
- declare -r name
檢視只讀變數:
readonly –p
1.4 補充:()、{ }的用處
( list ):一次性執行執行(相當於開了個子程序bash,執行後又回到父程序
[[email protected] ~]#( umask 666;touch /data/f1 ) #相當於開了一個子shell,umask改為666後建立了一個檔案f1,然後再返回到父shell
[[email protected] ~]#ll -d /data/f1
----------. 1 root root 0 Nov 29 14:49 /data/f1
[[email protected] ~]#( name=songtai;echo $name )
songtai
{ list }:大括號直接作用於當前shell
[[email protected] ~]#name=songtai
[[email protected] ~]#( name=sun;echo $name )
sun
[[email protected] ~]#echo $name
songtai
[[email protected] ~]#{ name=sst;echo $name; } # 注意後邊跟;號
sst
[[email protected] ~]#x=1;echo $$;( echo $$;echo $x;x=2;echo $x );echo $x
13196
13196 # 注意;兩個子程序號相同,說明()開的子程序與重新開個子shell還是有不同
1
2
1
1.5位置變數和特殊變數
位置變數:在指令碼程式碼中呼叫通過命令列傳遞給指令碼的引數
$?:上一條程式碼執行的回傳指令,回傳0表示標準輸出,即正確執行,否則為標準錯誤輸出。
>> 對於指令碼中的回傳指令是0還是其他,看指令碼的最後一條命令,如果有標準輸出就是0.否則是其他數值;注意語法錯誤與命令錯誤的區分。
exit [n]:自定義退出狀態碼
$$:當前shell的PID。除了執行bash命令和shell指令碼時,$$不會繼承父shell的值,其他型別的子shell都繼承。
$BASHPID:當前shell的PID,這和"$$"是不同的,因為每個shell的$BASHPID是獨立的。而"$$"有時候會繼承父shell的值。
$!:最近一次執行的後臺程序PID。
$#:統計引數的個數。
[email protected]:所有單個引數,如"a""b""c""d"。
$*:所有引數的整體,如“abcd”。
$0:指令碼名。 注意:對軟連結,$0 顯示的是軟連結的名稱
$1……$n:引數位置。
示例:
vim /bin/args.sh # 編寫指令碼 /bin/args.sh
#!/bin/bash
echo "1st arg is $1"
echo "2st arg is $2"
echo "3st arg is $3"
echo "4st arg is $4"
echo "all args is $*"
echo "all args is [email protected]"
echo "the args number is $#"
echo "the script is `basename $0`"
[[email protected] ~]#args.sh aaa nne ewd q
1st arg is aaa
2st arg is nne
3st arg is ewd
4st arg is q
all args is aaa nne ewd q
all args is aaa nne ewd q
the args numbers is 4
the script is args.sh
shfit 換位置,預設換一個。
示例:
vim args.sh # 編輯指令碼
#!/bin/bash
echo "1st arg is $1"
echo "2st arg is $2"
echo "3st arg is $3"
echo "4st arg is $4"
echo "all args is $*"
echo "all args is [email protected]"
echo "the args numbers is $#"
echo "the script is $0"
shift
echo "1st arg is $1"
echo "2st arg is $2"
echo "3st arg is $3"
echo "4st arg is $4"
echo "all args is $*"
echo "all args is [email protected]"
echo "the args numbers is $#"
echo "the script is $0"
shift
echo "1st arg is $1"
echo "2st arg is $2"
echo "3st arg is $3"
echo "4st arg is $4"
echo "all args is $*"
echo "all args is [email protected]"
echo "the args numbers is $#"
echo "the script is $0"
shift # 儲存退出指令碼
[[email protected] bin]#args.sh a b c d # 執行指令碼args.sh a b c d
1st arg is a
2st arg is b
3st arg is c
4st arg is d
all args is a b c d
all args is a b c d
the args numbers is 4 # 4個引數
the script is /root/bin/args.sh
1st arg is b
2st arg is c
3st arg is d
4st arg is
all args is b c d
all args is b c d
the args numbers is 3 # 第一個引數去掉,後3個引數依次向前
the script is /root/bin/args.sh
1st arg is c
2st arg is d
3st arg is
4st arg is
all args is c d
all args is c d
the args numbers is 2 # 依上一步的引數,第一個仍然去掉,後2個依次向前
the script is /root/bin/args.sh
注意:當引數達到10以上時,用 ${10} 表示第10個引數 ,否則系統會將10都城
字元1和0的組合。
實驗:編寫指令碼/root/bin/sumid.sh,計算/etc/passwd檔案中的第10個使用者和第20使用者的ID之和。
#!/bin/bash
UID1="`head -n$1 /etc/passwd | cut -d: -f3 |tail -n1`"
UID2="`head -n$2 /etc/passwd | cut -d: -f3 |tail -n1`"
sumid=$[$UID1+$UID2]
echo $sumid
此指令碼有個問題,直接執行sumid.sh不跟引數的話會報錯。改良如下:
#!/bin/bash
[ $# -ne 2 ] && echo "Args num must be 2" && exit # 引數數量為2個,則接著執行後邊的命令;引數數量不為2,則執行“Args num must be 2”,然後退出!
UID1="`head -n$1 /etc/passwd | cut -d: -f3 |tail -n1`"
UID2="`head -n$2 /etc/passwd | cut -d: -f3 |tail -n1`"
sumid=$[$UID1+$UID2]
echo $sumid
繼續改良:
#!/bin/bash
[ $# -ne 2 ] && echo "Args num must be 2" && exit
[[ ! "$1" =~ ^[0-9]+$ ]] && echo "$1 is not digital" && exit
[[ ! "$2" =~ ^[0-9]+$ ]] && echo "$2 is not digital" && exit
UID1="`head -n$1 /etc/passwd | cut -d: -f3 |tail -n1`"
UID2="`head -n$2 /etc/passwd | cut -d: -f3 |tail -n1`"
sumid=$[$UID1+$UID2]
echo $sumid
二、運算
2.1算術預算
bash中的算術運算:help、let
+, -,*, /, %取模(取餘), **(乘方)
實現算術運算:
(1) let var=算術表示式
x=10
y=20
let z=x+y 或 let z=\$x+\$y
echo $z
30
let x++
echo $x
11
let ++x
echo $x
12
(2) var=$[算術表示式]
n=8
m=5
sum=$[n+m] 或 sum=$[$n+$m]
echo $sum
13
(3) var=$((算術表示式))
(4) var=$(expr arg1 arg2 arg3 ...)
注意:
expr 1 + 2 字元之間有空格
expr 1 * 2 *需要轉義符
(5) declare –i var = 數值
declare -i x=10
declare -i y=20
echo -i z=x+y
echo $z
30
(6) echo ‘算術表示式’ | bc
注意:乘法符號有些場景中需要轉義
(7)bash有內建的隨機數生成器:$RANDOM(0-32767)
echo $[$RANDOM%50]
:0-49之間隨機數
示例:
COLOR=$[RANDOM%7+31] 或 COLOR=$((RANDOM%7+31))
echo $COLOR 一直是一個數值,除非再執行一次上一條命令,就會換一個數值????
echo -e "\e[1;${COLOR}mcolor\e[0m"
COLOR="$[RANDOM%7+31]";echo -e "\e[1;${COLOR}mcolor\e[0m"
color隨機變色
(8) 賦值
增強型賦值:+=, -=, *=, /=, %=
例如:
let x+=2 表示為x+2後自賦值
自增,自減:
let var+=1
let var++ x+1後自賦值
let var-=1
let var--
2.2 邏輯運算
1.真假表示
true : 1
false :0
非:!
!0=1
!1=0
2.&、| 運算
&: and,與運算;有一個假就全假,全是真才為真
0 & 0 = 0
0 & 1 = 0
1 & 0 = 0
1 & 1 = 1
| : or,或運算;全是假才是假,有一個真就是真
0 | 0 = 0
0 | 1 = 1
1 | 0 = 1
1 | 1 = 1
3.&& 短路與;|| 短路或
&& 短路與
0 && 0 = 0
0 && 1 = 0
1 && 0 = 0
1 && 1 = 1
cmd1 && cmd2 :
- cmd1若為假,那麼cmd2就不需要執行,因為最終結果都為假
- cmd1若為真,那麼cmd2需要執行,才能判斷最終結果。
|| 短路或
0 || 0 = 0
0 || 1 = 1
1 || 0 = 1
1 || 1 = 1
cmd1 || cmd2 :
- cmd1若為假,那麼cmd2需要執行,才能判斷最終結果。
- cmd1若為真,那麼cmd2不需要執行,因為最終結果都為真。
cmd1 && cmd2 || cmd3
cmd1為假,那麼cmd1&&cmd2 的結果必為假,所以需要執行cmd3,才能判斷最終結果。
cmd1為真,那麼要執行cmd2,才能判斷cmd1 && cmd2的結果,若cmd2為真,不執行cmd3,若cmd2為假,執行cmd3.
x=haha;y=xixi;[ $x = $y ] && echo equal || echo qual
^ XOR,抑或:
1 ^ 0 = 1
1 ^ 1 = 0
0 ^ 1 = 1
0 ^ 0 = 0
^異或的兩個值,相同為假,不同為真
^ 的應用示例:兩個數互換
a=4 # 4二進位制表示為 100
b=6 # 6二進位制表示為 110
let c=a^b
echo $c
1
a、b的值互換示例:
a=4
b=6
a=$[a^b];b=$[a^b];a=[a^b];echo $a $b # 第一個分號左側a為a^b的值;第二個分號左側b為第一個a的值與b抑或為4(a);第三個分號的[]中,a為a^b的值,b為4,所以左側的a為6(b)。
6 4
2.3 test
- test EXPRESSION
- [ EXPRESSION ]
- [[ EXPRESSION ]]
注意:EXPRESSION前後必須有空白字元
(1)比較字串
option:
-z STRING True if string is empty.-n STRING True if string is not empty.
STRING1 = STRING2 True if the strings are equal.
STRING1 != STRING2 True if the strings are not equal. 不等於
STRING1 < STRING2 True if STRING1 sorts before STRING2 lexicographically. ascii碼是否小於ascii碼
STRING1 > STRING2 True if STRING1 sorts after STRING2 lexicographically.
STRING1 =~ STRING2 左側字串是否能夠被右側的PATTERN所匹配
- 注意: 此表示式一般用於[[ ]]中;擴充套件的正則表示式
str1=aaa
str2=bbb
test $str1 $str2
echo $?
1
注意:
test $str1 $str2
[ $str1 = str2 ]
[[ str1 = str2 ]] #這個三個表示式的效果相同,注意第二個與第三個裡面的空格!
實驗:判斷一個字串是否為空的字串:
[ -z string ]
[ x"$string" = "x" ]
[ $string = ]
(2)比較數字
-eq equal,相等
-ne not equal,不想等
-lt less than,小於
-le less equal,小於等於
-gt graeter than 大於
-ge greater equal 大於等於
實驗:寫指令碼,磁碟利用率大於80報警;
#!/bin/bash
DF_USER="`df | grep "dev/sd" | tr -s " " % | cut -d% -f5 |sort -nr | head -n1`"
[ "$DF_USER" -ge 80 ] && echo warmming!! # 注意:[] 內的變數要用“”引起來!!
(3) 檔案比較
> -a FILE True if file exists.
-b FILE True if file is block special.
-c FILE True if file is character special.
-d FILE True if file is a directory.
-e FILE True if file exists.
-f FILE True if file exists and is a regular file.
-g FILE True if file is set-group-id.
-h FILE True if file is a symbolic link.
-L FILE True if file is a symbolic link.
-k FILE True if file has its `sticky' bit set.
-p FILE True if file is a named pipe.
-r FILE True if file is readable by you.
-s FILE True if file exists and is not empty.
-S FILE True if file is a socket.
-t FD True if FD is opened on a terminal.檔案描述符是否在某終端已經開啟
-u FILE True if the file is set-user-id.
-w FILE True if the file is writable by you. 是否有寫許可權
-x FILE True if the file is executable by you.
-O FILE True if the file is effectively owned by you. 你是否屬於該檔案屬主
-G FILE True if the file is effectively owned by your group.
-N FILE True if the file has been modified since it was last read.檔案自從上一次被讀取之後是否被修改過
-u FILE: 是否存在且擁有suid許可權
-g FILE: 是否存在且擁有sgid許可權
-k FILE: 是否存在且擁有sticky許可權
FILE1 -nt FILE2 True if file1 is newer than file2 (according to modification date).
FILE1 -ot FILE2 True if file1 is older than file2.
FILE1 -ef FILE2 True if file1 is a hard link to file2.
實驗:建立使用者,如果該使用者存在則不建立,如果不存在建立之,並將“magedu”作為其密碼。
#1/bin/bash
[ $# -ne 1 ] && echo "your args is wrong" && exit
id $1 &> /dev/null && echo "$1 is exist" && exit || useradd $1 && echo "magedu" | passwd --stdin $1
或
#!/bin/bash
id $1 &> /dev/null
[ $? -eq 0 ] && echo "$1 is exist" && exit
useradd $1 && echo magedu | passwd --stdin $1
(4) bash的組合測試檔案
第一種方式:
COMMAND1 && COMMAND2 並且
COMMAND1 || COMMAND2 或者
! COMMAND 非
如:[[ -r FILE ]] && [[ -w FILE ]]
第二種方式:
EXPRESSION1 -a EXPRESSION2 並且
EXPRESSION1 -o EXPRESSION2 或者
! EXPRESSION
必須使用測試命令進行
示例:
[ -z “$HOSTNAME” -o $HOSTNAME "==\"localhost.localdomain" ] && hostname www.magedu.com
[ -f /bin/cat -a -x /bin/cat ] && cat /etc/fstab
三、read
使用read來把輸入值分配給一個或多個shell變數
-p 指定要顯示的提示
-s 靜默輸入,一般用於密碼
-n N 指定輸入的字元長度N
-d ‘字元’ 輸入結束符
-t N TIMEOUT為N秒
#!/bin/bash
read -p "please input your name: " name
echo your name is $name
#!/bin/bash
read -p "please input your name: " name
read -s -p "please input your passwd: " passwd
echo your name is $name
echo your passwd is $passwd
實驗:雞兔同籠;輸入總的頭數和總的腳數,算出雞、兔分別有幾隻。
#!/bin/bash
read -p "please input heads num: " H
read -p "please input feets num: " F
C=$[(4*H-F)/2]
R=$[(F-2*H)/2]
echo "the chicken num is $C"
echo "the rabbir num is $R"