一、bash中的變數類型
本地變數:僅對當前shell有效,對其子shell無效
變數賦值:name=value
name=$user
name=`Command` ,name=$(Command):這裡需要注意的是“ 和 $()的意義是不同的。
從下圖可以總結如下:如果將命令的執行結果賦值給一個參數時,且包含多對反引號嵌套的時候,最好外層用$()
#!/bin/bash
#
Sum=$(echo `seq $1 $2` | tr " " "+" | bc) #################可以正確輸出
echo "$1到$2的和為:$Sum"
Sum1=`echo `seq $1 $2` | tr " " "+" | bc` #################輸出報錯
echo "$1到$2的和為:$Sum1"
root@cenots6.8 /testdir # ./13sum.sh 1 100
1到100的和為:5050
./13sum.sh: command substitution: line 7: syntax error near unexpected token `|'
./13sum.sh: command substitution: line 7: ` | tr " " "+" | bc'
./13sum.sh: line 7: 1: command not found
1到100的和為:
root@cenots6.8 /testdir # echo `seq 1 10`
1 2 3 4 5 6 7 8 9 10
root@cenots6.8 /testdir # echo `echo `seq 1 10``
seq 1 10
root@cenots6.8 /testdir # echo $(echo `seq 1 10`)
1 2 3 4 5 6 7 8 9 10
root@cenots6.8 /testdir # echo "echo `seq 1 10`"
echo 1
2
3
4
5
6
7
8
9
10
變數引用:$name,${name}
顯示已定義的所有變數:set
刪除變數:unset name
環境變數:對當前shell及其子shell有效
變數賦值:export name=value
declare -x name=value
顯示所有環境變數:export、env、printenv
刪除變數:unset name
bash內建的環境變數有:PATH, SHELL, USRE,UID,HISTSIZE, HOME, PWD, OLDPWD, HISTFILE, PS1
局部變數:對當前shell進程中某段程式碼片段有效(通常指函數)
位置變數:$1 $2……表示,用於讓指令碼在指令碼代碼中通過調用命令列中的傳遞的參數,1和2 分別代表第一個參數和第二個參數,shift可以替換參數
特殊變數:$?:判斷執行結果0-255
$0:指令碼名稱
$*:命令列中傳遞的所有參數,且當做一個整體
$@:命令列傳遞的所有參數,每個參數當做一個整體
$#:命令列中傳遞的參數總數,與$@只在被雙引號包起來才會看出差異,可從下段指令碼中看去區別
root@Centos7.2 /testdir # cat arg1.sh arg2.sh
#!/bin/bash
#
echo 1st is $1
echo 2st is $2
echo all args are is "$*"
#!/bin/bash
#
./arg1.sh "$*"
echo ============i
./arg1.sh "$@"
echo ==============
echo $*
echo $@
root@Centos7.2 /testdir # ./arg2.sh 1 2 3
1st is 1 2 3
2st is
all args are is 1 2 3
============i
1st is 1
2st is 2
all args are is 1 2 3
==============
1 2 3
1 2 3
唯讀變數:唯讀變數不能修改刪除
變數賦值:readonly name=value 、declare -r name=value
PATH變數定義位置:.bash_profile –> $PATH:$HOME/bin
PATH=$PATH:$HOME/.local/bin:$HOME/bin –.local/bin centos7普通使用者有的隱藏的目錄,可以放寫隱藏的指令碼
寫指令碼的時候可以先mkdir /home/bin 在bin目錄下寫指令碼,可省去相對路徑。
source bash.sh 也可以執行指令碼:其執行過程相當於直接在當前shell進程中進行,而不是開一個子進程進行,所有指令碼執行完,echo 變數,還可以查看到變數的值。(正常父進程是不能查看子進程的變數的)
shadow 預設許可權000 但是root使用者屬於超級使用者 可讀可寫,但是如果檔案沒有x許可權,root也不能執行
二、算數運算子
bash中的算數運算子:+、-、*、/、%、**(平方) 注意:在使用expr的時候“*” 要轉義“\*”
實現算數運算:
let var=算數運算式
var=$[算數運算式]
var=$((算數運算式))
var=$(expr arg1 arg2 arg3) 注意:每個參數之間要用空格隔開
root@cenots6.8 # echo $(expr 5 \* 2 - 1)
9
declare -i var=數字
echo ‘算數運算式’| bc
隨機數產生器:echo $[RANDOM%50]:0-49之間的隨機數
echo $[RANDOM%50+1]:1-50之間的隨機數
$RANDOM :1-32767
三、彙總命令
#!/bin/bash
echo xxx;(echo zzz;exit) ############():代表開個子shell,exit退出子shell非當前shell
echo yyy
四、退出狀態代碼
0 代表成功, 1-255代表失敗
$? 變數儲存最近的命令退出狀態
我們也可以指定程式退出的狀態代碼,根據狀態代碼的數值,來判斷工作狀態,指令碼中一旦遇到exit命令,指令碼會立即終止,終止,終止退出狀態取決於exit命令後面的數字,如果沒有執行exit,則取指令碼最後一條命令的執行狀態結果。
五、條件測試
測試命令:test [expression]
[ $a = $b ] 判斷 一對[]或兩對[[]] 都可以
[[ $a == $b ]] 兩個等號也可以
[ -f /bin/cat -a -x /bin/cat ] 此時必須使用 一對[] 否則會報錯
數值測試:
-gt:大於
-ge:大於等於
-lt:小於
-le:小於等於
-eq:等於
-ne:不等於
字串測試:
==:是否相等
>:大於(比較ascll碼)
<:小於
!=:是否不等於
=~:左側字串是否能夠被右側的PATTERN所匹配,注意: 此運算式一般用於[[ ]]中;
-z “string”:判斷字串是否為空白,如果為空白則為真
-n “string”:判斷字串是否為空白,如果不為空白則為真
注意:用於字串比較的時候,運算元應該使用引號
存在性測試:
-a file:檔案存在為真,否則為假
-e file:同-a
存在性及類別測試:
-b FILE:是否存在且為塊裝置檔案 block
-c FILE:是否存在且為字元裝置檔案 char
-d FILE:是否存在且為目錄檔案 dir
-f FILE:是否存在且為普通檔案
-h FILE 或 -L FILE:存在且為符號連結檔案
-p FILE:是否存在且為具名管道檔案
-S FILE:是否存在且為通訊端檔案
檔案許可權測試:
-r FILE:是否存在且可讀
-w FILE: 是否存在且可寫
-x FILE: 是否存在且可執行
檔案特殊許可權測試:
-g FILE:是否存在且擁有sgid許可權
-u FILE:是否存在且擁有suid許可權
-k FILE:是否存在且擁有sticky許可權
檔案大小測試:
-s FILE: 是否存在,非空為真,否則為假
檔案是否開啟:
-t fd: fd表示檔案描述符是否已經開啟且與某終端相關
-N FILE:檔案自動上一次被讀取之後是否被修改過
-O FILE:當前有效使用者是否為檔案屬主
-G FILE:當前有效使用者是否為檔案屬組
雙目測試:
FILE1 -ef FILE2: FILE1與FILE2是否指向同一個裝置上的相同inode
FILE1 -nt FILE2: FILE1是否新於FILE2;
FILE1 -ot FILE2: FILE1是否舊於FILE2;
組合測試條件:
第一種方式:
COMMAND1 && COMMAND2 並且
COMMAND1 || COMMAND2 或者
! COMMAND 非
如: [ -e FILE ] && [ -r FILE ]
第二種方式:
EXPRESSION1 -a EXPRESSION2 並且
EXPRESSION1 -o EXPRESSION2 或者
! EXPRESSION
一、作業:
1、編寫指令碼/root/bin/systeminfo.sh,顯示當前主機系統資訊,包括主機名稱,IPv4地址,作業系統版本,核心版本,CPU型號,記憶體大小,硬碟大小。
#!/bin/bash
#編寫指令碼/root/bin/systeminfo.sh,顯示當前主機系統資訊,包括主機名稱,IPv4地址,作業系統版本,核心版本,CPU型號,記憶體大小,硬碟大小。
IPaddr=`ifconfig | sed -n '2p'| sed 's@.*inet addr:@@g' | sed 's@Bc.*@@'`
SysVersion=`cat /etc/redhat-release`
CPU=`sed -n "5p" /proc/cpuinfo |cut -d: -f2|tr -d " "`
MemInfo=`sed -n '1p' /proc/meminfo |cut -d: -f2|tr -d " "`
FdiskInfo=`fdisk -l |sed -n '2p' | grep -o ".*GB"| sed -r "s@Dis.*: @@"`
echo "HostName: `hostname`"
echo "Ipaddress: $IPaddr"
echo "SysVersion: $SysVersion"
echo "KernelVersion: `uname -r`"
echo "CPU: $CPU"
echo "MemInfo: $MemInfo"
echo "FdiskInfo: $FdiskInfo"
unset IPaddr
unset SysVersion
unset CPU
unset MemInfo
unset FdiskInfo
root@cenots6.8 /testdir # ./systeminfo.sh
HostName: cenots6.8
Ipaddress: 10.1.249.49
SysVersion: CentOS release 6.8 (Final)
KernelVersion: 2.6.32-642.el6.x86_64
CPU: Intel(R)Core(TM)i5-5200UCPU@2.20GHz
MemInfo: 1004136kB
FdiskInfo: 128.8 GB
2、編寫指令碼/root/bin/backup.sh,可實現每日將/etc/目錄備份到/root/etcYYYY-mm-dd中
#!/bin/bash
#編寫指令碼/root/bin/backup.sh,可實現每日將/etc/目錄備份到/root/etcYYYY-mm-dd中
dirName="/root/etc`date +%F`"
cp -a /etc $dirName && echo " 備份成功"
root@cenots6.8 /testdir # ls -d ~/etc* ; du -sh ~/etc*
/root/etc2016-08-12
41M /root/etc2016-08-12
3、編寫指令碼/root/bin/disk.sh,顯示當前硬碟分區中空間利用率最大的值
#!/bin/bash
#編寫指令碼/root/bin/disk.sh,顯示當前硬碟分區中空間利用率最大的值
Use=`df | tr -s " "|cut -d" " -f5|sed -n '1!p'|sort -n|tr -d % |tail -1`
[ $Use -gt 10 ] && wall disk will be full!
unset Use
root@cenots6.8 /testdir # ./checkdisk.sh
Broadcast message from root@cenots6.8 (pts/1) (Fri Aug 12 10:38:52 2016):
disk will be full
4、編寫指令碼/root/bin/links.sh,顯示正串連本主機的每個遠程主機的IPv4地址和串連數,並按串連數從大到小排序
#!/bin/bash
#編寫指令碼/root/bin/links.sh,顯示正串連本主機的每個遠程主機的IPv4地址和串連數,並按串連數從大到小排序
linCount=`netstat -t | grep "tcp" | tr -s " " | cut -d" " -f5 | sed "s@:.*@@" | sort -n | uniq -c`
echo -e “連結數 IP地址”
echo -e "$linCount"
root@cenots6.8 /testdir # ./links.sh
“連結數 IP地址”
2 10.1.250.130
5、寫一個指令碼/root/bin/sumid.sh,計算/etc/passwd檔案中的第10個使用者和第20使用者的ID之和
#!/bin/bash
#寫一個指令碼/root/bin/sumid.sh,計算/etc/passwd檔案中的第10個使用者和第20使用者的ID之和
UserId10="`sed -n '10p' /etc/passwd | cut -d: -f3`"
UserId20="`sed -n '20p' /etc/passwd | cut -d: -f3`"
SumId=$[UserId10+UserId20]
echo "第10個使用者和第20使用者的ID之和為:$SumId"
unset UserId10
unset UserId20
unset SumId
root@cenots6.8 /testdir # ./sumid.sh
第10個使用者和第20使用者的ID之和為:180
6、寫一個指令碼/root/bin/sumspace.sh,傳遞兩個檔案路徑作為參數給指令碼,計算這兩個檔案中所有空白行之和
#!/bin/bash
#寫一個指令碼/root/bin/sumspace.sh,傳遞兩個檔案路徑作為參數給指令碼,計算這兩個檔案中所有空白行之和
File1="`grep "^$" $1 | wc -l`"
File2="`grep "^$" $2 | wc -l`"
SpaceSum=$[File1+File2]
echo "兩個檔案中所有空白行之和: $SpaceSum "
unset File1
unset File2
unset SpaceSum
root@cenots6.8 /testdir # ./sumspace.sh /etc/profile /etc/fstab
兩個檔案中所有空白行之和: 12
7、寫一個指令碼/root/bin/sumfile.sh,統計/etc, /var, /usr目錄中共有多少個一級子目錄和檔案
#!/bin/bash
#寫一個指令碼/root/bin/sumfile.sh,統計/etc, /var, /usr目錄中共有多少個一級子目錄和檔案#
EtcNum="`ls /etc/ | wc -l`"
VarNum="`ls /var/ | wc -l`"
UsrNum="`ls /usr/ | wc -l`"
SumFile=$[$EtcNum+$VarNum+$UsrNum]
echo "The Sumfile: $SumFile"
unset EtcNum
unset VarNum
unset UsrNum
unset SumFile
root@cenots6.8 /testdir # ./sumfile.sh
The Sumfile: 287
8、寫一個指令碼/root/bin/argsnum.sh,接受一個檔案路徑作為參數;如果參數個數小於1,則提示使用者“至少應該給一個參數”,並立即退出;如果參數個數不小於1,則顯示第一個參數所指向的檔案中的空白行數
#!/bin/bash
#寫一個指令碼/root/bin/argsnum.sh,接受一個檔案路徑作為參數;如果參數個數小於1,則提示使用者“至少應該給一個參數”,並立即退出;如果參數個數不小於1,則顯示第一個參
數所指向的檔案中的空白行數
[[ $# -lt 1 ]] && echo "至少應該給一個參數" || echo "SpaceNum: `grep "^$" $1 | wc -l`"
root@cenots6.8 /testdir # ./argsnum.sh
至少應該給一個參數
root@cenots6.8 /testdir # ./argsnum.sh /etc/profile
SpaceNum: 11
9、寫一個指令碼/root/bin/hostping.sh,接受一個主機的IPv4地址做為參數,測試是否可連通。如果能ping通,則提示使用者“該IP地址可訪問”;如果不可ping通,則提示使用者“該IP地址不可訪問”
#!/bin/bash
#
ping -c1 -W2 $1 &> /dev/null && echo "該IP地址可訪問" || echo "該IP地址不可訪問"
root@cenots6.8 /testdir # ./hostping.sh 10.1.249.48
該IP地址可訪問
root@cenots6.8 /testdir # ./hostping.sh 10.1.249.4
該IP地址不可訪問
10、chmod -rw /tmp/file1,編寫指令碼/root/bin/per.sh,判斷目前使用者對/tmp/fiile1檔案是否不可讀且不可寫
#!/bin/bash
#
[ -r /testdir/file1 -a -w /testdir/file1 ] && echo "`whoami` 可讀可寫" || echo "`whoami`非可讀可寫"
root@cenots6.8 /testdir # ./per.sh
root 可讀可寫
tom@cenots6.8 /testdir # ./per.sh
tom非可讀可寫
11、編寫指令碼/root/bin/nologin.sh和login.sh,實現禁止和充許普通使用者登入系統。
#!/bin/bash
#編寫指令碼/root/bin/nologin.sh和login.sh,實現禁止和充許普通使用者登入系統。
[ ! -f /etc/nologin ] && echo "普通使用者已不可以登陸系統" && touch /etc/nologin
[ -f /etc/nologin ] && echo "普通使用者已可以登陸系統" && rm -rf /etc/nologin
root@cenots6.8 /testdir # ./login.sh #########################禁止普通使用者登陸
普通使用者已不可以登陸系統
[c:\~]$ ssh tom@10.1.249.49
Connecting to 10.1.249.49:22...
Connection established.
To escape to local shell, press 'Ctrl+Alt+]'.
Connection closed by foreign host.
Disconnected from remote host(10.1.249.49:22) at 12:09:27.
Type `help' to learn how to use Xshell prompt.
root@cenots6.8 /testdir # ./login.sh ##########################允許普通使用者登陸
普通使用者已可以登陸系統
[c:\~]$ ssh tom@10.1.249.49
Connecting to 10.1.249.49:22...
Connection established.
To escape to local shell, press 'Ctrl+Alt+]'.
tom@cenots6.8 ~ #
12、寫一個指令碼/root/bin/hostping.sh,接受一個主機的IPv4地址做為參數,先判斷是否合格IP,否,提示IP格式不合法並退出,是,測試是否可連通。如果能ping通,則提示使用者“該IP地址可訪問”;如果不可ping通,則提示使用者“該IP地址不可訪問”
#!/bin/bash
#
echo "$1" | grep -E -qo '(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])' && ( ping -c1 -W2 $1 &> /dev/null && echo "該IP地址可以訪問" || echo "該IP地址不可以訪問") || echo "該IP地址不合法";exit 1
root@cenots6.8 /testdir # ./hostping.sh
該IP地址不合法
root@cenots6.8 /testdir # ./hostping.sh 10.1.249.49
該IP地址可以訪問
root@cenots6.8 /testdir # ./hostping.sh 192.192.192.192
該IP地址不可以訪問
13、計算1+2+3+…+100的值
#!/bin/bash
#
Num=`echo {1..100} | tr " " "+" | bc`
echo "$1到$2的和為:$Num"
root@cenots6.8 /testdir # ./13sum.sh
到的和為:5050
#!/bin/bash
#
Sum=$(echo `seq $1 $2` | tr " " "+" | bc)
echo "$1到$2的和為:$Sum"
root@cenots6.8 /testdir # ./13sum.sh 1 100
1到100的和為:5050
14、計算從指令碼第一參數A開始,到第二個參數B的所有數位總和,判斷B是否大於A,否提示錯誤並退出,是則計算之
#!/bin/bash
#計算從指令碼第一參數A開始,到第二個參數B的所有數位總和,判斷B是否大於A,否提示錯誤並退出,是則計算之
Sum=$(echo `seq $1 $100` | tr " " "+" | bc)
[ $1 -lt $2 ] && echo $1到$2的和為:$Sum || echo "$1 不能大於 $2" ;exit 1
root@cenots6.8 /testdir # ./14sum.sh 1 100
1到100的和為:5050
root@cenots6.8 /testdir # ./14sum.sh 100 1
100 不能大於 1