文章目錄
BASH基礎
Shell爲Linux提供了編程環境
程序 = 指令 + 數據
編程風格:
過程式:以指令爲中心,數據服務於命令
對象式:以數據爲中心,命令服務於數據
shell是一種過程式編程
過程式編程:
順序執行
循環執行
選擇執行
如何判斷shell腳本: 文件中頭行: #!/bin/bash 標識
運行腳本方法:
給文件給予可執行權限,通過具體的文件路徑執行文件執行
chmod +x xxx.sh
./path/to/xxx.sh
直接運行解釋器,將腳本作爲解釋器程序的參數運行
bash xx.sh
[root@node1 ~]# echo $PATH
/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/root/
系統運行命令尋找的路徑,如果你將腳本文件放入到以上路徑下,可以將腳本直接作爲命令去執行。
變量
變量命名:
命名只能使用英文字母,數字,下劃線;首字母不能以數字開頭
中間不能夠有空格,可以使用_下換線
不能夠使用標點符號(特殊字符)
不能夠使用bash中的關鍵字
有效的命名:
RUNshell
L_inux
var1
無效的命名:
?var1
user*name
賦值
將語句給變量賦值
for file in “ls /etc/”
for file in $(ls /etc/)
[root@node1 ~]# for file in "ls /tmp/";do echo $file;done
將文件路徑/tmp/下的所有文件賦給變量file,do…;done之間是循環體。
該條命令是循環顯示/tmp/下的文件名。
使用變量:
定義變量: varname=“value”
使用變量: echo $varname | echo ${varname}
建議:使用{}作爲邊界
只讀變量:
readonly關鍵字可以將變量作爲只讀變量,變量無法被修改
[root@node1 ~]# vim 1.sh
在裏面寫入
#!/bin/bash
url="www.baidu.com"
echo ${url}
url="www.google.com"
echo ${url}
把"www.baidu.com"賦值給變量url,使用變量
再把"www.google.com"賦值給變量url,使用變量
然後給1.sh執行權限
[root@node1 ~]# chmod +x 1.sh
接下來直接執行" ./1.sh ",會輸出
"www.baidu.com"
"www.google.com"
如果將1.sh修改爲
#!/bin/bash
url="www.baidu.com"
echo ${url}
readonly url
url="www.google.com"
echo ${url}
就會輸出兩次"www.baidu.com"並報錯,因爲url是隻讀變量了所以不能被修改。
刪除變量:unset關鍵字
#!/bin/bash
url="www.baidu.com"
echo ${url}
unset url
echo ${url}
此時執行" ./1.sh “,第一次輸出"www.baidu.com”,第二次爲空。
變量的種類:
本地變量:生效範圍僅作爲當前shell進程(其他shell或者子shell無法使用)
例如將a=1,echo$a就是1;然後bash進入子shell,再echo $a就是空值。
[root@node1 ~]# a=1
[root@node1 ~]# echo ${a}
1
[root@node1 ~]# bash # 進入到子shell中
[root@node1 ~]# echo ${a}
環境變量:生效範圍爲當前shell進程及子進程
變量聲明方式1: export varname=“value”
變量聲明方式2: declare -x varname=“value”
bash當中有很多內建的環境變量: PATH SHELL
局部變量:生效範圍爲當前shell進程中某代碼片段(通常函數)
位置變量:1,2,3…來表示,讓腳本在腳本片段中調用通過命令行傳遞給他的參數。
用法: ./xx.sh 參數1 參數2 參數3 …
調用:
$1,$2,$3: 對應的是參數1,參數2,參數3....
$0: 對應是命令本身
$*: 傳遞給腳本的所有參數(把所有參數當成一個整體)
$@: 傳遞給腳本的所有參數
$#: 傳遞給腳本的參數個數
案例1:
[root@node1 ~]# cat 1.sh
#!/bin/bash
echo ${1}
echo ${2}
echo $0
echo $*
echo $@
echo $# ·
[root@node1 ~]# ./1.sh Linux Python
Linux
Python
./1.sh
Linux Python
Linux Python
2
案例2:判斷所給文件的行數
判斷anaconda-ks.cfg文件的行數
[root@node1 ~]# wc -l anaconda-ks.cfg | awk '{print $1}'
48
[root@node1 ~]# cat linecount.sh
#!/bin/bash
lines=`wc -l $1 | awk '{print $1}'`
echo "This file have ${lines} line"
特殊變量:? 0 * @ $ # 等等
shell數組
語法格式:
定義:array_name=(value1 value2 …)
使用:array_name[0]
示例1:
array_1=(A B C)
array_1[0]=A
array_1[1]=B
array_1[2]=C
讀取數組: ${array_name[index]}
修改數組中的元素:
array_1[index]=N_value
讀取數組中的所有元素:
${array_name[*]}
${array_name[@]}
讀取數組中的所有元素個數:
${#array_name[*]}
${#array_name[@]}
實例:
#!/bin/bash
array_1=(A B C D)
echo ${array_1[0]}
echo ${array_1[3]}
echo ${array_1[*]}
echo ${array_1[@]}
echo ${#array_1[*]}
echo ${#array_1[@]}
shell的環境配置
bash配置文件
- 生效範圍分類:
全局配置:/etc/profile /etc/profile.d/* /etc/bashrc
個人配置: ~/.bashrc ~/.bash_profile
功能:
- 用於定義環境變量
- 運行命令或腳本
- 功能分類:
- profile類:爲交互式的shell提供配置
全局配置:/etc/profile /etc/profile.d/*
個人配置:~/.bash_profile - bashrc類:爲非交互式的shell提供配置
全局配置:/etc/bashrc
個人配置:~/.bashrc
功能: 定義本地變量
-
shell登錄:
交互式: su - Username
/etc/profile -> /etc/profile.d/* -> ~/.bash_profile
非交互式: su Username
~/.bashrc -> /etc/bashrc編輯環境配置文件: 定義的新設置立即生效: 1. 重新啓動shell 2. source命令 -> source /etc/profile
bash算數運算符
算數運算符: + - * / …
增強型: += -= *= /= %=
使用算數符:
(1)let varname=算數表達式
(2)varname=$[算數表達式]
(3)varname=$((算數表達式))
(4)varname=$( expr arg1 arg2 arg3 …)
Note:
乘法符號* 有些情況下需要轉義 *
bash中有個內建隨機生成器: $RANDOM
練習題
- 計算/etc/passwd文件中第10行的用戶ID和第20行的用戶ID和
#!/bin/bash
id1=`cat /etc/passwd | head -n 10 | tail -1 | awk -F: '{print $3}'`
id2=`sed -n '20p' /etc/passwd | cut -d: -f3`
let sum_id="id1+id2"
echo $sum_id
head -n 10是前十行,再加上tail -1纔是第十行。然後用awk命令過濾,awk -F指定‘:’作爲分隔符打印第三個字段,即11。
sed -n '20p’打印文件的第二十行,cut -d指定以‘:’爲分隔符,-f3爲提取第個三域。
- 傳遞兩個文件文件參數給腳本,計算這兩個文件之中所有空白之和
#!/bin/bash
blank1=`cat $1 | grep "^$" | wc -l`
blank2=`cat $2 | grep "^$" | wc -l`
let sum_blank=blank1+blank2
echo $sum_blank
其中“$1”“$2”是傳入的文件名參數,執行腳本文件是就可以寫成:
./sum_blank.sh 文件名1 文件名2
grep引號中的第一個字符^和最後一個$:
^: 表示字符串開始。
$: 表示字符串結束。
grep "^$"表示精確匹配文件中的空格
wc指令我們可以計算文件的Byte數、字數、或是列數,wc -l只顯示行數。
- 統計/etc/,/var/,/usr/目錄下所有一級目錄和文件之和
#!/bin/bash
sum_etc=`ls /etc/ | wc -l`
sum_var=`ls /var/ | wc -l`
sum_usr=`ls /usr/ | wc -l`
let sum_all="sum_etc+sum_usr+sum_usr"
echo $sum_all
條件測試
bash條件測試:
判斷某些需求是否滿足,需要由測試機制來實現
專用的測試表達式需要由命令輔助完成測試過程
測試命令: test Experssion
- 測試類型:
數值測試
字符串測試
文件測試
數值測試:
-gt 是否大於
-ge 是否大於等於
-eq 是否等於
-ne 是否不等
-lt 是否小於
-le 是否小於等於
字符串測試:
== : 是否等於
> : 是否大於
< : 是否小於
!=: 是否不等於
=~ : 左側字符串是否能被右側的Pattern匹配
Note: 此表達式一般用於 [[]]中
-z “String” : 測試字符串是否爲空,空則爲真;非空則爲假
-n “String” : 測試字符串是否不空,不空爲真;空則爲假
文件測試:
簡單存在性測試:
-a file: 文件存在則爲正,不存在則爲假
存在及類型測試:
-b file: 是否存在且爲塊設備文件
-c file: 是否存在且爲字符設備文件
-d file: 是否存在且爲目錄文件
-f file: 是否存在且爲普通文件
-h file: 是否存在且爲符號鏈接文件(-l 可以)
-p file: 是否存在且爲管道文件
-s file: 是否存在且爲socket文件
文件權限測試:
-r file: 是否存在可讀權限
-w file:是否存在可寫權限
-x file:是否存在可執行權限
文件特殊權限測試:
-g file: 是否存在且擁有sgid權限
-u file: 是否存在且擁有suid權限
-k file: 是否存在且擁有sticky權限
文件大小測試:
-s file: 是否存在且非非空
文件是否打開測試:
- fd : fd表示文件愛你描述是否已經打開且與終端相關
-N file: 文件自動上一次讀取之後是否被修改過
-O file:當前用戶是否爲文件屬主
-G file:當前用戶是否爲文件數組
雙目測試:
file1 -ef file2: file1與file2是否指向同一個設上的相關inode
file1 -nt file2: file1是否新於file2
file1 -ot file2: file1是否舊於file2
組合測試條件:
- 第一種方式: && ||
&& 全真則爲真
|| 有真則爲真 - 第二種方式:
-a -> && -> experssion1 && experssion2
-o -> || -> experssion1 || experssion2
! Experssion
bash退出碼
腳本中一旦遇到exit命令,腳本會立即終止,終止退出碼取決於exit命令後面的數字
如果腳本中未給出退出碼,整個腳本的退出碼由最後腳本中最後一行命令的執行結果決定
exit N
練習1: 接收一個文本路徑作爲參數,如果參數個數小於1,則提示用戶“至少給1個參數”,並立即退出
[ $# -lt 1 ] && echo "at least one args ...." && exit 1
$#判斷傳給腳本的參數個數,小於1就打印“at least one args”並退出,退出碼爲1。
[ $# -gt 1 ] && echo "test ok ...." && exit 0
於是我們可以根據退出碼知道執行情況。
Note: 使用條件測試的時候;[ experssion ]; 條件測試表達式experssion與中括號兩邊是有空格的
選擇執行:
語法:
-
第一種:
if 判斷條件;then
條件爲真的執行代碼塊
fi -
第二種:
if 判斷條件;then
條件爲真的執行代碼塊
else
條件爲假的執行代碼塊
fi -
第三種:
if 判斷條件1;then
條件爲真的代碼塊
elif 判斷條件2;then
條件1爲假;條件2爲真的執行代碼塊
else
條件12都爲假的執行代碼塊
fi
練習1: 判斷兩個數是否相等
#!/bin/sh
set num1 = $1
set num2 = $2
#這個判斷如何寫?
if test $num1 -eq $num2
then
echo "num1 is equal to num2"
else
echo "num1 is not equal to num2"
fi;
練習2: 判斷用戶是否存在,如果不存在添加用戶並設置密碼和用戶名相同;如果存在立即退出;退出狀態碼爲0
#!/bin/bash
#定義函數
Find_u(){
#判斷輸入值是否爲空,如果爲空,則函數結束,返回值1
[ -z $1 ] && return 1
#判斷用戶是否存在,存在則顯示要求,不存在,函數結束,返回值1
if id $1 &> /dev/null ;then
echo "$1 UID is `id -u $1`"
echo "$1 Shell is `grep "^$1:" /etc/passwd \
|cut -d':' -f7 `"
else
return 1
fi
}
#循環執行,以符合題目要求
while :;do
read -p "Please input A username[quit to exit]: " User
if [ $User = quit ];then
exit 0
else
Find_u $User
Res=$?
[ $Res -eq 1 ] && echo "No such $User."
fi
done
知識點: 命令的使用 -> 條件測試 + 選擇執行結構 + 狀態碼
用戶交互
read命令
-a : 將內容讀取寫入到數組中
[root@localhost ~]# read -a array_test1
hello linux test
[root@localhost ~]# echo "get ${#array_test1[*]} values in array"
get 3 values in array
-d : 表示定界符;
-e : 只用於互相交互的腳本
-n : 用於限定最多可以有多少個字符有效讀入
-p : 用於給出提示符
echo -n "please input value into array_test "
read -a array_test
或直接
read -p “please input value into array_test…” array_test
示例:
[root@node1 ~]# cat read.sh
#!/bin/bash
read -p "please input one number ......" number1
echo $number1
其中number1是用於接收用戶輸入的。
-r : 特殊字符生效
-s :對於一些特殊字符不打印的情況
-t :表示等待輸入的時間時長
練習1: 輸入姓名之後,進行輸出
#!/bin/bash
read -p "Input your name" name
echo ${name}
練習2:輸入一個文件判斷文件類型,判斷輸入文件是否爲目錄文件;是則輸出yes;否則直接退出
#!/bin/bash
read -p "please input your test file ...." file
if [ -d file ];then
echo "this is a directory file ...."
exit 0
else
echo "this is not a directory file ..."
exit 1
fi
運用條件測試中的具體命令可解決類似題目,可到上文條件測試去看具體命令。
循環結構
循環體: 需要執行的語句,可能執行n遍
for循環
語法:
for 變量名 in 列表;do
循環體
done
執行機制:依次將列表中的元素賦值給變量名然後去執行一遍循環體;當列表中的元素耗盡時,退出
示例:
[root@node1 ~]# for i in `ls /tmp/`;do echo $i;done
循環輸出/tmp/下的文件名
[root@node1 ~]# for i in {20,30};do ping -c4 192.168.10.$i;done
分別循環ping 192.168.10.20 和 192.168.10.30 ,輸出4行
[root@node1 ~]# for i in `seq 1 10`;do echo $i;done
seq 數字生成器:m到n數字
練習題1: 創建用戶user1-user10家目錄,並且在user1-user10家目錄下創建1.txt - 10.txt文件內容,輸出格式爲
練習題2: 列出/var/目錄下各個子目錄所佔磁盤大小
while循環
語法:
while 條件測試;do
循環體
done
執行機制: 當條件測試爲真是就執行一遍循環體;爲假時退出循環
經典使用:讀取文件中的內容
寫法1:
#!/bin/bash
while read linecontext;do
echo "+++$linecontext"
done < /root/test.txt
寫法2:
cat $1 | while read linecontext
do
echo $linecount
done
until循環
執行機制:條件爲假時執行循環體;條件爲真時退出
語法:
until 條件測試;do
循環體
done
函數
函數定義:
function Fun_name(){
函數體
返回值
}
調用函數:Fun_name
示例1:
#!/bin/bash
function sum_b(){
blank1=`cat $1 | grep "^$" | wc -l`
blank2=`cat $2 | grep "^$" | wc -l`
let sum_blank=blank1+blank2
echo $sum_blank
return 0
}
#調用函數 傳入參數
sum_b $1 $2
返回值的獲取: 可以通過 echo $?來獲取
總結
shell腳本編程要對命令熟悉,通過對命令的組合進行shell編程。
shell腳本應用:通過shell成當前資源(cpu disk vm …)的使用情況 每天都需要統計。