shell 編程 入門 到 實戰 詳解

一. shell變量、循環

概述

    Shell是一種具備特殊功能的程序,它提供了用戶與內核進行交互操作的一種接口。它接收用戶輸入的命令,並把它送入內核去執行。內核是Linux系統的心臟,從開機自檢就駐留在計算機的內存中,直到計算機關閉爲止,而用戶的應用程序存儲在計算機的硬盤上,僅當需要時才被調入內存。Shell是一種應用程序,當用戶登錄Linux系統時,Shell就會被調入內存去執行。Shell獨立於內核,它是連接內核和應用程序的橋樑,並由輸入設備讀取命令,再將其轉爲計算機可以理解的機械碼,Linux內核才能執行該命令。

優勢

Shell腳本語言的好處是簡單、易學、易用,適合處理文件和目錄之類的對象,以簡單的方式快速完成某些複雜的事情通常是創建腳本的重要原則,腳本語言的特性可以總結爲以下幾個方面:

1. 語法和結構通常比較簡單。
2. 學習和使用通常比較簡單,
3. 通常以容易修改程序的“解釋”作爲運行方式,而不需要“編譯。
4. 程序的開發產能優於運行效能。

Shell腳本語言是Linux/Unix系統上一種重要的腳本語言,在Linux/Unix領域應用極爲廣泛,熟練掌握Shell腳本語言是一個優秀的Linux/Unix開發者和系統管理員必經之路。利用Shell腳本語言可以簡潔地實現複雜的操作,而且Shell腳本程序往往可以在不同版本的Linux/Unix系統上通用。

1.基本格式:

Shell腳本的文件名後綴通常是.sh (當然你也可以使用其他後綴或者沒有後綴,.sh是爲了規範)

程序編寫格式:

#!/bin/bash
#  註釋使用#號

代碼示例:

使用vi編輯器編寫shell腳本(a.sh不存在則會新建)
vi a.sh

進入vi編輯模式後編寫執行代碼

固定格式,記住就可以了
#!/bin/bash
執行的代碼
echo Hello World

賦予權限並執行:

賦予可執行權限
chmod +x a.sh
執行(調用/bin/bash執行a.sh腳本)
./a.sh
sh a.sh

執行結果:

[root@python ~]# ./a.sh 
Hello world

bash 語法檢查

[root@python ~]# bash -x a.sh 
+ echo Hello world
Hello world

2.變量

變量不需要聲明,初始化不需要指定類型

2.1 變量命名

- 只能使用數字,字母和下劃線,且不能以數字開頭
- 變量名區分大小寫
- 建議命令要通俗易懂

注意:變量賦值是通過等號(=)進行賦值,在變量、等號和值之間不能出現空格。

顯示變量值使用echo命令(類似於java中的system.out) ,加上變量名,也可以使用{變量名}

變量的申明和使用:

[root@python ~]# num=10
[root@python ~]# echo $num
10

2.2 變量分類

Shell變量有這幾類:本地變量、環境變量、局部變量、位置變量、特殊變量。

- 只對當前shell進程有效的,對當前進程的子進程和其它shell進程無效。
- 定義:VAR_NAME=VALUE
- 變量引用:{VAR_NAME} 或者 VAR_NAME
- 取消變量:unset VAR_NAME
- 只能當前類使用,子類和其他類都無法使用。

在一個bash命令窗口下再使用bash,則變成了子進程,本地變量不會被這個子進程所訪問

[root@python ~]# num=10
[root@python ~]# echo $num
10
[root@python ~]# bash
[root@python ~]# echo $unm

[root@python ~]# 

2.3 環境變量

自定義的環境變量對當前shell進程及其子shell進程有效,對其它的shell進程無效

定義:export VAR_NAME=VALUE

對所有shell進程都有效需要配置到配置文件中

[root@python ~]# vim /etc/profile
[root@python ~]# source /etc/profile

2.4自定義的環境變量

[root@python ~]# export name=xiaoming
[root@python ~]# echo $name
xiaoming
[root@python ~]# bash
[root@python ~]# echo $name
xiaoming

2.5局部變量

  1. 在函數中調用,函數執行結束,變量就會消失
  2. 對shell腳本中某代碼片段有效
  3. 定義:local VAR_NAME=VALUE

2.6位置變量

比如腳本中的參數:

Linux中變量$#,$@,$0,$1,$2,$*,$$,$?的含義?
$# 是傳給腳本的參數個數
$0 是腳本本身的名字
$1 是傳遞給該shell腳本的第一個參數
$2 是傳遞給該shell腳本的第二個參數

$@ 是傳給腳本的所有參數的列表
$* 是以一個單字符串顯示所有向腳本傳遞的參數,與位置變量不同,參數可超過9個
$$ 是腳本運行的當前進程ID號Linux中變量$#,$@,$0,$1,$2,$*,$$,$?的含義
$? 是顯示最後命令的退出狀態,0表示沒有錯誤,其他表示有錯誤

編寫腳本:

[root@python ~]# cat variable.sh 
#!/bin/sh

echo "number:$#"
echo "scname:$0"
echo "first :$1"
echo "second:$2"
echo "argume:$@"

echo "show parm list:$*"
echo "show process id:$$"
echo "show precomm stat: $?"

執行示例:

[root@python ~]# ./variable.sh 
number:0
scname:./variable.sh
first :
second:
argume:
show parm list:
show process id:1445
show precomm stat: 0

2.7 引號

Shell編程中有三類引號:單引號、雙引號、反引號。

###1.’'單引號
不解析變量

[root@python ~]# echo '$name'
$name

###2.""雙引號
會解析變量

[root@python ~]# echo "$name"
xiaoming

###3.``反引號

是執行並引用一個命令的執行結果,類似於$(…)

[root@python ~]# echo `$name`
bash: xiaoming: command not found

3. 循環

3.1 for循環

通過使用一個變量去遍歷給定列表中的每個元素,在每次變量賦值時執行一次循環體,直至賦值完成所有元素退出循環

格式 1
for ((i=0;i<10;i++))
do
  ...
Done
格式 2
for i in 0 1 2 3 4 5 6 7 8 9
do
...
Done

示例

#!/bin/bash
day="sun mon  tue wen fri sat "
for x in $day
do
	echo "the day is : $x"
done

格式 3

for i in {0..9}
do
  ...
done

注意:for i in {0…9} 等於for i in {0…9…1} , 第三個參數爲跨步

示例

#!/bin/bash
day="sun mon  tue wen fri sat "
for x in $day
do
	echo "the day is : $x"
done

3.2 while循環

適用於循環次數未知,或不便用for直接生成較大的列表時

格式
while 測試條件
do
循環體
done

如果測試條件爲“真”,則進入循環,測試條件爲假,則退出循環。

[root@python ~]# cat while.sh 
#!/bin/bash
num=0
while [ $num -lt 10 ]
do
echo $num
let num=$num+1
done

打印結果

[root@python ~]# sh while.sh 
0
1
2
3
4
5
6
7
8
9

4.循環控制

4.1 循環控制命令——break

break命令是在處理過程中跳出循環的一種簡單方法,可以使用break命令退出任何類型的循環,包括while循環和for循環

4.2 循環控制命令——continue

continue命令是一種提前停止循環內命令,而不完全終止循環的方法,這就需要在循環內設置shell不執行命令的條件

5 條件

5.1 bash條件測試

格式:

test EXPR
[ EXPR ]:注意中括號和表達式之間的空格

5.2 整型測試:

-gt:大於:
-lt:小於
-ge:大於等於
-le:小於等於
-eq:等於
-ne:不等於

例如[ $num1 -gt $num2 ]或者test $num1 -gt $num2

5.3 字符串測試:

=:等於,例如判斷變量是否爲空 [ "$str" =  "" ] 或者[ -z $str ]
!=:不等於

示例:

[root@python ~]# cat str.sh 
#!/bin/bash
num1=4
num2=5
str1=Alice
str2=Bob
if [ $num1 -gt $num2 ]
then
echo num1 large than num2
else
echo num1 lower than num2
fi

if [ -z $str1 ]
then
echo str1 is empty
else
echo str is not empty
fi

執行結果:

[root@python ~]# sh str.sh 
num1 lower than num2
str is not empty

6.判斷

6.1 單分支

 if 測試條件;then
選擇分支
fi
#!/bin/bash

if [ $USER != root ];then
echo "erro:not root user,permission deny"
exit 127
fi

6.2 雙分支

if 測試條件
  then
   選擇分支1
   else
   選擇分支2
 fi

6.3 多分支

 if 條件1; then
           分支1
 elif 條件2; then
           分支2
 elif 條件3; then
           分支3
          ...
 else
           分支n
 fi

示例:

#!/bin/bash
read -p "input a file name:" file_name
if [ -d $file_name ];then
	echo "$file_name is a directory"
elif [ -f $file_name ];then
	echo "$file_name is a file"
elif [ -c $file_name ];then
	echo "$file_name is a devices"
else
	echo "$file_name is unknown file"
fi7.**Case判斷** 

7.case語句會使得語法結構更清晰

7.1格式

case 變量引用 in
               PATTERN1)
                         分支1
                         ;;
               PATTERN2)
                         分支2
                         ;;
               ...
               *)
                         分支n
                         ;;
               esac

PATTERN :類同於文件名通配機制,但支持使用|表示或者

a|b:a或者b

*:匹配任意長度的任意字符

?:匹配任意單個字符

[a-z]:指定範圍內的任意單個字符

7.2示例

[root@python ~]# cat case.sh 
#!/bin/bash
num=10
case $num in
	1)
		echo 1
			;;
	2)
		echo 2
			;;
	10)
		echo 10
			;;
	*)
		echo somethine else
			;;
esac

8.算術運算

let varName=算術表達式
varName=$[算術表達式]
varName=$((算術表達式))
varName=`expr $num1 + $num2`
使用這種格式要注意兩個數字和+號中間要有空格。

8.1示例

[root@centos7 ~]# num=2
[root@centos7 ~]# let num=$num+1
[root@centos7 ~]# echo $num
3

[root@centos7 ~]# num=2
[root@centos7 ~]# num=$[ $num+1 ]
[root@centos7 ~]# echo $num
3
[root@centos7 ~]# num=2
[root@centos7 ~]# num=$(($num+1))
[root@centos7 ~]# echo $num
3
[root@centos7 ~]# num=2
[root@centos7 ~]# num=`expr $num + 1`
[root@centos7 ~]# echo $num
3

8.2 邏輯運算符

8.2.1邏輯與

需要用到shell中的邏輯操作符

-a 與
-o 或
! 非
如if [ 條件A -a 條件B ] 

示例

[root@python ~]# cat num_1.sh 
#!/bin/bash
num1=10
num2=20
num3=15
if [ $num1 -lt $num3 -a $num2 -gt $num3 ]
then
	echo "num is between 10 and 20"
else
	echo "something else"
fi
8.2.2 邏輯或

#####示例


#!/bin/bash
num1=10
num2=20
num3=15
if [ $num1 -ge $num3 -o $num2 -lt $num3 ]
then
       echo "num is between 10 and 20"
else
       echo "something else"
fi

9.自定義函數

9.1 格式:

function 函數名(){
...
}
引用自定義函數文件時,使用source  func.sh
有利於代碼的重用性
函數傳遞參數(args[1]代表Shell中的$1)
函數的返回值,只能是數字
[root@python ~]# cat func.sh 
#!/bin/bash
function func(){
	echo this is function
}
func

9.2.函數的調用:

[root@python ~]# cat  func2.sh
#!/bin/bash
source /root/func.sh
func

9.3 read

read命令接收標準輸入(鍵盤)的輸入,或者其他文件描述符的輸入。得到輸入後,read命令將數據放入一個標準變量中。

格式

read VAR_NAME

read如果後面不指定變量,那麼read命令會將接收到的數據放置在環境變量REPLY中

#表示輸入時的提示字符串:
read -p "Enter your name:" VAR_NAME
[root@python ~]# read -p  "Enter you name:" name
Enter you name:
[root@python ~]# read -t 5 -p  "Enter you name:" name
Enter you name:[root@python ~]# 

# -t表示輸入等待的時間
read -t 5 -p "enter your name:" VAR_NAME
[root@python ~]# read -s -p  "Enter your password:" pass
Enter your password:

9.4 declare

用來限定變量的屬性

-r 只讀
-i 整數:某些算術計算允許在被聲明爲整數的變量中完成,而不需要特別使用expr或let來完成。
-a 數組

示例:

9.4.1 只讀
[root@python ~]# num=10
[root@python ~]# declare -r num
[root@python ~]# num=20
bash: num: readonly variable
[root@python ~]# 
9.4.2 整數
[root@python ~]# num4=10
[root@python ~]# num4=$num4+1
[root@python ~]# echo $num4
10+1
[root@python ~]# declare  -i num5
[root@python ~]# num5=10
[root@python ~]# num5=$num5+1
[root@python ~]# echo $num5
11
9.4.3 數組
[root@python ~]# declare  -a arr
[root@python ~]# arr=(1 2 3 4 5)
[root@python ~]# echo ${arr[*]}
1 2 3 4 5

10. 字符段操作

10.1 獲取長度:

${#VAR_NAME}
[root@python ~]# name=Alice
[root@python ~]# echo ${#name}
5

10.2 字符串截取

${variable:offset:length}或者${variable:offset}
[root@python ~]# name=Alice
[root@python ~]# echo ${name:0:3}
Ali

10.3 取尾部的指定個數的字符

${variable: -length}:注意冒號後面有空格
[root@python ~]# name=Alice
[root@python ~]# echo ${name:2}
ice

10.4 大小寫轉換

小—>大:

${variable^^}
[root@python ~]# name=Alice
[root@python ~]# echo ${name^^}
ALICE

大—>小

${variable,,}
[root@python ~]# name=Alice
[root@python ~]# echo ${name,,}
alice

10.5 數組

定義:declare -a:表示定義普通數組

特點

- 支持稀疏格式
- 僅支持一維數組

**數組賦值方式 **

- 一次對一個元素賦值a[0]=$RANDOM
-  一次對多個元素賦值a=(a b c d)

按索引進行賦值a=([0]=a [3]=b [1]=c)

使用read命令read -a ARRAY_NAME查看元素

${ARRAY[index]}:查看數組指定角標的元素
${ARRAY}:查看數組的第一個元素
${ARRAY[*]}或者${ARRAY[@]}:查看數組的所有元素

獲取數組的長度

${#ARRAY[*]}
${#ARRAY[@]}

獲取數組內元素的長度

${#ARRAY[0]}
注意:${#ARRAY[0]}表示獲取數組中的第一個元素的長度,等於${#ARRAY}

從數組中獲取某一片段之內的元素(操作類似於字符串操作)

格式:

${ARRAY[@]:offset:length}
  • offset:偏移的元素個數
  • length:取出的元素的個數
  • ${ARRAY[@]:offset:length}:取出偏移量後的指定個數的元素
  • ${ARRAY[@]:offset}:取出數組中偏移量後的所有元素

數組刪除元素:

unset ARRAY[index]

示例:

[root@python ~]# declare -a arr2
[root@python ~]# arr2=(a b c d )
[root@python ~]# arr2[1]=x
[root@python ~]# echo ${arr2[*]}
a x c d
[root@python ~]# echo ${#arr2[*]}
4
[root@python ~]# echo ${#arr2[1]}
1
[root@python ~]# echo ${arr2[1]}
x

二.shell 常用命令及參數

1.date

顯示當前時間

1. 格式化輸出 +%Y-%m-%d
2. 格式%s表示自1970-01-01 00:00:00以來的秒數
3. 指定時間輸出  --date='2009-01-01 11:11:11'
4. 指定時間輸出  --date='3 days ago'3天之前,3天之後可以用-3

示例:

[root@python ~]# echo `date +%Y-%m-%d-%H:%M:%S`
2018-08-25-14:07:16
[root@python ~]# echo `date +%s`
1535220472
[root@python ~]# echo `date --date='2009-01-01 11:11:11'`
Thu Jan 1 11:11:11 EST 2009
[root@python ~]# echo `date --date='3 days ago'`
Wed Aug 22 14:10:28 EDT 2018

2.後臺運行腳本

在腳本後面加一個&

test.sh &

這樣的話雖然可以在後臺運行,但是當用戶註銷(logout)或者網絡斷開時,終端會收到Linux HUP信號(hangup)信號從而關閉其所有子進程 ]

3.nohup命令

不掛斷的運行命令,忽略所有掛斷(hangup)信號

nohup test.sh &
  1. nohup會忽略進程的hangup掛斷信號,所以關閉當前會話窗口不會停止這個進程的執行。
  2. nohup會在當前執行的目錄生成一個nohup.out日誌文件

4.標準輸入、輸出、錯誤、重定向

標準輸入、輸出、錯誤可以使用文件描述符0、1、2引用

使用重定向可以把信息重定向到其他位置

1. ls >file 或者 ls 1>file(ls >>file)
2. lk 2>file(lk是一個錯誤命令)
3. ls >file 2>&1
4. ls > /dev/null(把輸出信息重定向到無底洞)

示例

command  >/dev/null 2>&1

5.Crontab定時器

  1. linux下的定時任務
  2. 編輯使用crontab -e
  3. 一共6列,分別是:分 時 日 月 周 命令

示例 表示每分鐘執行一次bash /root/bash.sh 命令

* * * * * bash /root/bash.sh

查看定時任務

[root@python ~]# crontab  -l
* * * * * bash /root/bash.sh

刪定時任務

[root@python ~]# crontab  -l
* * * * * bash /root/bash.sh
[root@python ~]# crontab  -r
You have new mail in /var/spool/mail/root
[root@python ~]# crontab  -l
no crontab for root

查看crontab執行日誌

[root@python ~]# tail -f /var/log/cron 

必須打開rsyslog服務cron文件中才會有執行日誌(service rsyslog status)

[root@python ~]# tail -f /var/spool/mail/root (查看crontab執行的情況)

查看cron服務狀態

[root@python ~]# service crond status

啓動cron服務

[root@python ~]# service crond start

基本示例:

基本格式 :

*  *  *  *  *  command

分 時  日  月   周   命令
第1列表示分鐘1~59 每分鐘用*或者 */1表示
第2列表示小時1~23(0表示0點)
第3列表示日期1~31
第4列表示月份1~12
第5列標識號星期0~6(0表示星期天)
第6列要運行的命令

crontab 示例:

30 21 * * * /usr/local/etc/rc.d/lighttpd restart
上面的例子表示每晚的21:30重啓apache。

45 4 1,10,22 * * /usr/local/etc/rc.d/lighttpd restart
上面的例子表示每月1、10、22日的4 : 45重啓apache。

10 1 * * 6,0 /usr/local/etc/rc.d/lighttpd restart
上面的例子表示每週六、週日的1 : 10重啓apache。 

0,30 18-23 * * * /usr/local/etc/rc.d/lighttpd restart
上面的例子表示在每天18 : 00至23 : 00之間每隔30分鐘重啓apache。

0 23 * * 6 /usr/local/etc/rc.d/lighttpd restart
上面的例子表示每星期六的11 : 00 pm重啓apache。

* */1 * * * /usr/local/etc/rc.d/lighttpd restart
每一小時重啓apache

* 23-7/1 * * * /usr/local/etc/rc.d/lighttpd restart
晚上11點到早上7點之間,每隔一小時重啓apache

0 11 4 * mon-wed /usr/local/etc/rc.d/lighttpd restart
每月的4號與每週一到週三的11點重啓apache

0 4 1 jan * /usr/local/etc/rc.d/lighttpd restart
一月一號的4點重啓apache

三. 登錄Shell和交互shell

交互式的:顧名思義,這種shell中的命令時由用戶從鍵盤交互式地輸入的,運行的結果也能夠輸出到終端顯示給用戶看。

 非交互式的:這種shell可能由某些自動化過程啓動,不能直接從請求用戶的輸入,也不能直接輸出結果給終端用戶看。輸出最好寫到文件。比如使用Shell腳本。

 登錄式:意思是這種是在某用戶由/bin/login登陸進系統後啓動的shell,跟這個用戶綁定。這個shell是用戶登陸後啓動的第一個進程。login進程在啓動shell時傳遞第0個參數指明shell的名字,該參數第一個字符爲"-",指明這是一個login shell。比如對bash而言,啓動參數爲"-bash"。

 非登錄式:不需login而由某些程序啓動的shell。傳遞給shell的參數,是沒有'-'前綴的。還以Bash爲例,當以非login方式啓動時,它會調用~/.bashrc,隨後~/.bashrc中調用/etc/bashrc,最後/etc/bashrc調用所有/etc/profile.d目錄下的腳本。

 一旦打開一個交互式login shell,或者以--login選項登錄的非交互式shell,都會首先加載並執行/etc/profile中的命令,然後再依次加載~/.bash_profile, ~/.bash_login, 和~/.profile中的命令。

 當bash以login shell啓動時,它會執行/etc/profile中的命令,然後/etc/profile調用/etc/profile.d目錄下的所有腳本;然後執行~/.bash_profile,~/.bash_profile調用~/.bashrc,最後~/.bashrc又調用/etc/bashrc。要識別一個shell是否爲login shell,只需在該shell下執行echo $0。

 注意: /etc/profile中的設置只對Login Shell生效,而crontab運行腳本的shell環境是non-login的,不會加載/etc/profile的設置。

四.shell 應用示例

1.系統優化腳本

需求:對CentOS6系統進行配置優化

Optimization_host.sh

#!/bin/bash
#time 20161122
#2016-11-30 by innocence_caosm
#此腳本在centos6.8上面試運行沒有問題,其他版本慎用!!!
#注意:
#1、縮進問題
#2、嚴謹性
#3、精簡至上原則   
Ipaddr(){
echo -e "\033[32;1m========================配置ip地址以及主機名稱======================================\033[0m"
read -p "請輸入你的ip地址:" IPADDR
read -p "請輸入你的子網掩碼:" NETMASK
read -p "請輸入你的網關地址:" GATEWAY
read -p "請輸入你的DNS1:" DNS1

sed -i  '/^ONBOOT/s/no/yes/' /etc/sysconfig/network-scripts/ifcfg-eth0
sed -i  '/^BOOTPROTO/s/dhcp/static/' /etc/sysconfig/network-scripts/ifcfg-eth0
sed -i "/^IPADDR/s/[0-9].\+/$IPADDR/ "  /etc/sysconfig/network-scripts/ifcfg-eth0
sed -i "/^NETMASK/s/[0-9].\+/$NETMASK/ "  /etc/sysconfig/network-scripts/ifcfg-eth0
sed -i "/^GATEWAY/s/[0-9].\+/$GATEWAY/ "  /etc/sysconfig/network-scripts/ifcfg-eth0
sed -i "/^DNS1/s/[0-9].\+/$DNS1/ "  /etc/sysconfig/network-scripts/ifcfg-eth0
service  network restart >&/dev/null
ping -c 3 -w 5 www.baidu.com >&/dev/null
if  [[ $? != 0 ]];then
echo " 不能上網請檢查配置 "
else
echo -e "\033[32;1m=====================NetWork Already Configure Finish ============================\033[0m"
fi
sleep 2
}
Ip_hostname(){
echo -e "\033[32;1m==========================配置主機名稱==============================================\033[0m"
read  -p "請輸入你的主機名稱:" HOSTNAME
sed -i '3,$d' /etc/hosts
sed -i '2,$d' /etc/sysconfig/network
sed -i  '/^HOSTNAME.*$/d' /etc/hosts
echo "HOSTNAME=$HOSTNAME" >> /etc/sysconfig/network
IPADDR=`ip a  | grep "global eth0" | awk '{print $2}' | awk -F "/" '{print $1}'`
echo -e "$IPADDR\t$HOSTNAME" >>/etc/hosts
echo -e "\033[32;1m===========================主機名配置成功==========================================\033[0m"
echo ""
sleep 2
}
# yum_163
ConfigYum(){
echo -e "\033[32;1m===========================更新爲國內YUM源==========================================\033[0m"
cd /etc/yum.repos.d/
    ping -c 1 www.163.com>/dev/null
if [ $? -eq 0 ];then
        mv CentOS6-Base-163.repo{,.$(date +%F)}
wget -q  http://mirrors.163.com/.help/CentOS6-Base-163.repo >/dev/null
sleep 2
        sed -i "s/\$releasever/6.8/g" CentOS6-Base-163.repo
        #sed -i '/s/$releasever/6.8/g' CentOS6-Base-163.repo   #此處可提升爲判斷系統版本號,給出不同的版本節點
else
echo "無法連接網絡!!!!"
exit $?
fi
echo -e "\033[32;1m============================正在更新YUM源配置=======================================\033[0m"
yum clean all >>/dev/null
yum list >>/dev/null
#action "配置國內YUM完成"  /bin/true
echo -e "\033[32;1m======================================配置YUM源完成===============================\033[0m"
echo ""
sleep 2
}
#time sync
SyncSysTime(){
echo -e "\033[32;1m=========================================配置時間====================================\033[0m"
  \cp /var/spool/cron/root /var/spool/cron/root.$(date +%F) 2>/dev/null
  NTPDATE=`grep ntpdate /var/spool/cron/root 2>/dev/null |wc -l`
  if [ $NTPDATE -eq 0 ];then
    echo "#times sync by lee at $(date +%F)" >>/var/spool/cron/root
    echo "*/5 * * * * /usr/sbin/ntpdate time.windows.com >/dev/null 2>&1" >> /var/spool/cron/root
  fi
#action "配置時間同步完成" /bin/true
echo -e "\033[32;1m=========================================配置時間完成====================================\033[0m"
echo ""
  sleep 2
}
#Charset zh_CN.UTF-8
InitI18n(){
echo -e  "\033[32;1m======================================更改爲中文字符集===================================\033[0m"
  \cp /etc/sysconfig/i18n /etc/sysconfig/i18n.$(date +%F)
  echo "LANG="zh_CN.UTF-8"" >/etc/sysconfig/i18n
  source /etc/sysconfig/i18n
  echo '#cat /etc/sysconfig/i18n'
  grep LANG /etc/sysconfig/i18n
#action "更改字符集zh_CN.UTF-8完成" /bin/true
echo -e "\033[32;1m====================================更改爲中文字符集完成===================================\033[0m"
echo ""
  sleep 2
}
#Close Selinux and Iptables
Firewall(){
echo -e "\033[32;1m======================================禁用SELINUX及關閉防火牆=============================\033[0m"
cp /etc/selinux/config /etc/selinux/config.$(date +%F)
  /etc/init.d/iptables status >>/dev/null
  if [ $? -eq 0 ];then #判斷防火牆是否開啓,開啓時返回值是0
    /etc/init.d/iptables stop >>/dev/null
  fi
$(cat /etc/selinux/config |grep SELINUX=enforcing)
if [ $? -eq 0 ] ;then
    sed -i 's/SELINUX=enforcing/SELINUX=disabled/g' /etc/selinux/config
    setenforce 0
fi
#getenforce
#action "禁用selinux及關閉防火牆完成" /bin/true
echo -e "\033[32;1m======================================禁用SELINUX及關閉防火牆完成=============================\033[0m"
echo ""
  sleep 2
}
Yum(){
echo -e "\033[32;1m======================================安裝常用軟件=============================\033[0m"
yum  install -y lrzsz  nptdate    bash-completion  wget 
echo ""
  sleep 2
}
echo -e "\033[32;1m======================================安裝常用軟件完成=============================\033[0m"

Core(){
echo -e "\033[32;1m======================================內核參數調整=============================\033[0m"
# 內核參數調優
grep -q "fs.file-max = 6815744" /etc/sysctl.conf || cat >> /etc/sysctl.conf << EOF
########################################################################################################################
vm.swappiness = 0
vm.overcommit_memory = 1
net.core.rmem_default = 262144
net.core.rmem_max = 16777216
net.core.wmem_default = 262144
net.core.wmem_max = 16777216
net.core.somaxconn = 60000
net.core.netdev_max_backlog = 60000
net.ipv4.tcp_max_orphans = 60000
net.ipv4.tcp_orphan_retries = 3
net.ipv4.tcp_max_syn_backlog = 60000
net.ipv4.tcp_max_tw_buckets = 10000
net.ipv4.ip_local_port_range = 1024 65500
net.ipv4.tcp_tw_recycle = 1
net.ipv4.tcp_tw_reuse = 1
net.ipv4.tcp_syncookies = 1
net.ipv4.tcp_synack_retries = 1
net.ipv4.tcp_syn_retries = 1
net.ipv4.tcp_fin_timeout = 30
net.ipv4.tcp_keepalive_time = 1200
net.ipv4.tcp_mem = 786432 1048576 1572864
fs.aio-max-nr = 1048576
fs.file-max = 6815744
kernel.sem = 250 32000 100 10000
kernel.pid_max = 65536
fs.inotify.max_user_watches = 1048576
kernel.kptr_restrict = 1
kernel.ctrl-alt-del = 1
EOF
sysctl -p
# 提高系統打開文件數、打開進程數限制,減小默認棧空間大小限制
grep -q "* - nofile 1048576" /etc/security/limits.conf || cat >> /etc/security/limits.conf << EOF
########################################################################################################################
* - nofile 1048576
* - nproc  65536
* - stack  1024
EOF

# 提高Shell打開文件數、打開進程數限制,減小默認棧空間大小限制
grep -q "ulimit -n 1048576" /etc/profile || cat >> /etc/profile << EOF
########################################################################################################################
ulimit -n 1048576
ulimit -u 65536
ulimit -s 1024

alias grep='grep --color=auto'
export HISTTIMEFORMAT="%Y-%m-%d %H:%M:%S "
EOF

echo -e "\033[32;1m======================================內核參數調整完畢=============================\033[0m"

#menu2
menu2(){
while true
do
clear
cat << EOF
----------------------------------------
|****Please Enter Your Choice:[0-6]****|
----------------------------------------
(1) 配置ip地址以
(2) 配置爲國內YUM源鏡像
(3) 設置時間同步
(4) 配置中文字符集
(5) 禁用SELINUX及關閉防火牆
(6) 配置主機名稱
(0) 返回上一級菜單
EOF
read -p "Please enter your Choice[0-6]: " input2
case "$input2" in
  0)
  clear
  break
  ;;
  1)
  Ipaddr
  ;;
  2)
  ConfigYum
  ;;
  3)
  SyncSysTime
  ;;
  4)
  InitI18n
  ;;
  5)
  Firewall
  ;;
  6)
  Ip_hostname
  ;;
  *)
  Warning
  ;;
esac
done
}
#menu
main(){
while true
do
clear
echo "========================================"
echo '          Linux Optimization            '   
echo "========================================"
cat << EOF
|-----------System Infomation-----------
| DATE       :$DATE
| HOSTNAME   :$HOSTNAME
| USER       :$USER
| IP         :$IPADDR
| DISK_USED  :$DISK_SDA
| CPU_AVERAGE:$cpu_uptime
----------------------------------------
|****Please Enter Your Choice:[1-3]****|
----------------------------------------
(1) 一鍵優化
(2) 自定義優化
(3) 退出
EOF
#choice
read -p "Please enter your choice[0-3]: " input1
    case "$input1" in
    1)    
    Ipaddr
    ConfigYum
    SyncSysTime
    InitI18n
    Firewall
    Ip_hostname
        ;;
    2)
        menu2
        ;;
    3)
        clear
        break
        ;;
    *)   
   Warning
   ;;
    esac  
done
}
Warning(){
echo "----------------------------------"
  echo "|          Warning!!!            |"
  echo "|   Please Enter Right Choice!   |"
  echo "----------------------------------"
  sleep 2
((ErrorNo+=1))
    if [ $ErrorNo -eq 3 ];then  #判斷錯誤次數,已達到自動退出目的
        echo -e '\033[31;1mError So Much ,The Script  Exiting!\033[0m'
        sleep 5

        exit
    fi
  clear
}
if $UID != 0 ;then
echo 'must use Root run this script!'
else
#獲取一些初始變量,磁盤使用情況未配置
    ErrorNo=0
    DATE=$(date +%F)
    IPADDR=`ifconfig |grep Bcast|awk '{print $2}'|awk -F: '{print $2}'`
    DISK_SDA=`df -hT | grep '/$' | awk '{print $6}'`   
    cpu_uptime=`uptime|awk -F: '{print $4}'`
main
fi

CentOS7** 系統優化腳本

centos 7 優化 


#!/bin/bash
# 服務優化
grep -q '7.' /etc/redhat-release
if [ $? -ne 0 ]; then
Services=$(chkconfig --list | grep '0' | awk '{print $1}' | grep -Ev 'sshd|network|crond|syslog|ntpd')
for Service in $Services
do
service $Service stop
chkconfig --level 0123456 $Service off
done
else
Services=(atd avahi-daemon cups dmraid-activation firewalld irqbalance kdump mdmonitor postfix)
for Service in ${Services[*]}
do
systemctl disable ${Service}
systemctl stop ${Service}
done
systemctl enable rc-local
fi

# 內核參數調優
grep -q "fs.file-max = 6815744" /etc/sysctl.conf || cat >> /etc/sysctl.conf << EOF
########################################
vm.swappiness = 0
vm.overcommit_memory = 1
net.core.rmem_default = 262144
net.core.rmem_max = 16777216
net.core.wmem_default = 262144
net.core.wmem_max = 16777216
net.core.somaxconn = 60000
net.core.netdev_max_backlog = 60000
net.ipv4.tcp_max_orphans = 60000
net.ipv4.tcp_orphan_retries = 3
net.ipv4.tcp_max_syn_backlog = 60000
net.ipv4.tcp_max_tw_buckets = 10000
net.ipv4.ip_local_port_range = 1024 65500
net.ipv4.tcp_tw_recycle = 1
net.ipv4.tcp_tw_reuse = 1
net.ipv4.tcp_syncookies = 1
net.ipv4.tcp_synack_retries = 1
net.ipv4.tcp_syn_retries = 1
net.ipv4.tcp_fin_timeout = 30
net.ipv4.tcp_keepalive_time = 1200
net.ipv4.tcp_mem = 786432 1048576 1572864
fs.aio-max-nr = 1048576
fs.file-max = 6815744
kernel.sem = 250 32000 100 10000
kernel.pid_max = 65536
fs.inotify.max_user_watches = 1048576
kernel.kptr_restrict = 1
kernel.ctrl-alt-del = 1
EOF
sysctl -p

# 提高系統打開文件數、打開進程數限制,減小默認棧空間大小限制
grep -q "* - nofile 1048576" /etc/security/limits.conf || cat >> /etc/security/limits.conf << EOF
########################################
* - nofile 1048576
* - nproc 65536
* - stack 1024
EOF

# 提高Shell打開文件數、打開進程數限制,減小默認棧空間大小限制
grep -q "ulimit -n 1048576" /etc/profile || cat >> /etc/profile << EOF
########################################
ulimit -n 1048576
ulimit -u 65536
ulimit -s 1024

alias grep='grep --color=auto'
export HISTTIMEFORMAT="%Y-%m-%d %H:%M:%S "
EOF

# 禁用並關閉selinux
sed -i 's/SELINUX=enforcing/SELINUX=disabled/' /etc/selinux/config
setenforce 0

# 優化SSH服務
sed -i 's/.*UseDNS yes/UseDNS no/' /etc/ssh/sshd_config
sed -i 's/.*GSSAPIAuthentication yes/GSSAPIAuthentication no/' /etc/ssh/sshd_config
#sed -i '/^PasswordAuthentication/s/yes/no/' /etc/ssh/sshd_config
grep -q '7.' /etc/redhat-release
if [ $? -ne 0 ]; then
service sshd restart
else
systemctl restart sshd.service
fi

# 腳本目錄加入PATH環境變量
grep -q "/root/script" $HOME/.bashrc || cat >> $HOME/.bashrc << EOF
########################################
export PATH=/root/script:\$PATH
EOF

mkdir -p /root/script /root/src

# 掛載tmpfs文件系統
mount --bind /dev/shm /tmp
grep -q "mount --bind /dev/shm /tmp" /etc/rc.local || echo "mount --bind /dev/shm /tmp" >> /etc/rc.local

思路:

對剛安裝完成的虛擬主機進行優化處理,簡化工作流程
對服務進行優化
對防火牆 selinux進行優化
字符編碼進行優化
network進行優化
ssh 進行優化
yum 源進行優化
date 時間進行優化

2.自動部署zabbix 腳本

2017-11-29 17:25:54
#/bin/bash
#by innocence_caosm
#源碼自動安裝zabbix客戶端腳本。
#需要把zabbix安裝包放在/tmp/ 下面執行。 
#安裝gcc cc插件
#此腳本已在centos6.5以及6.8版本測試過,其他版本慎用。
yum install -y gcc cc

#需要注意修改的參數
server_ip=133.1.11.103
version=zabbix-3.2.7

#檢查zabbix用戶是否存在
user=zabbix
group=zabbix

#create group if not exists
egrep "^$group" /etc/group >& /dev/null
if [ $? -ne 0 ]
then
groupadd $group
fi

#create user if not exists
egrep "^$user" /etc/passwd >& /dev/null
if [ $? -ne 0 ]
then
useradd -g $group $user -s /sbin/nologin
echo zabbix |passwd --stdin $user >& /dev/null
fi

#檢查原有zabbix服務,如果有則停掉
ps -ef |grep zabbix|grep -v grep
if [ $? -eq 0 ]
then
/etc/init.d/zabbix-agent stop || /etc/init.d/zabbix-agentd stop
fi
#編譯安裝
tar -zxvf /tmp/$version.tar.gz -C /usr/local/src/;cd /usr/local/src/$version/
./configure --prefix=/usr/local/$version/ --enable-agent
make&&make install

#修改配置文件
sed -i.bak 's/127.0.0.1/$server_ip/g' /usr/local/$version/etc/zabbix_agentd.conf
hostname=cat /etc/sysconfig/network | sed -n '2p' | awk -F'=' '{print $2}'
sed -i "s/Hostname=Zabbix server/Hostname="$hostname"/g" /usr/local/$version/etc/zabbix_agentd.conf

#配置init.d啓動
cp /usr/local/src/$version/misc/init.d/fedora/core/zabbix_agentd /etc/init.d/zabbix_agentd
sed -i 's/BASEDIR=\/usr\/local/BASEDIR=\/usr\/local\/$version/g' /etc/init.d/zabbix_agentd
#配置開機啓動
chkconfig --add zabbix_agentd
chkconfig zabbix_agentd on
/etc/init.d/zabbix_agentd start
#查看zabbix啓動
netstat -lnp |grep zabbix
if [ $? -eq 0 ]
then
echo "Zabbix agent install have completed."
fi

思路:

由於需要批量部署zabbix 客戶端,簡化操作流程,在這樣的條件下寫了這個腳本。
1.安裝系統所需要的依賴插件
2.把客戶端源碼放在指定位置進行解壓處理
3.檢查系統用戶是否存在
4.對配置進行修改處理
5.啓動進行檢測

3.監控url 地址

[root@localhost opt]# cat web_url.sh 
#!/bin/bash
for i in `cat web_url`
do
curl=`curl -I -s $i |head -1|cut -d " " -f2`
if [ "$curl" == "200" ];then
    echo curl $i is ok
else
    echo "$i is fail" | mail -s "web fail url"  [email protected]
fi
done

[root@localhost opt]# cat web_url
http://192.168.0.123:8080/lemon/portal/index.do
http://192.168.0.123:8080/photo

思路:

由於內網環境處於調試初期階段,服務不穩定,需要對指定的幾個url進行做監控處理。
1.把需要儘快的url地址寫到文檔中
2.運用for循環來遍歷url地址
3.檢測狀態碼是否正常,正常則打印出來,不正常則把url 信息通過郵箱發送給管理員

4.nginx日誌距離當前時間20分鐘之內不同接口的訪問量統計

#!/bin/bash
#此腳本用於統計nginx日誌距離當前時間15分鐘之內不同接口的訪問量統計
LOG=/usr/local/nginx/logs/interface.access.log
TMP=/tmp/url.tmp
URLSTATS=/var/log/interface_urlstats.log
RECEIVERS="[email protected] [email protected] [email protected]"

#刪除臨時統計文件
[ -f $TMP ] && rm -fr $TMP

for i in `seq 20`
do
	d=`date +%d/%h/%Y:%H:%M  -d "$i minutes ago"`
	#將每個時間段的URL進行統計並追加到臨時文件
	awk -v b="$d" '{if ($4 ~ b)a[$7]++}END{for(i in a)printf("%-42s %-d\n", i,a[i])}' $LOG >> $TMP
done

#將彙總到臨時文件的URL統計進行彙總
if [ -s $TMP ];then
	awk '{a[$1]+=$2;}END{for(i in a)printf("%-42s %-d\n", i,a[i])}' $TMP | sort -nr -k2 > $URLSTATS
	mail -s "$(date +%F-%H:%M) 20分鐘內URL訪問量統計"  "$RECEIVERS" <$URLSTATS
else
	echo "需要統計的時間段日誌文件沒有被成功處理"
fi
1. 根據seq循環15次並調用date獲取最近的20分鐘的時間,
2. 使用awk進行過濾日誌並格式化打印,然後結合sort排序,
3. 最終過濾內容通過mail發送郵件

5.ngix日誌切割腳本

#!/bin/sh
set -x
logs_path="/usr/local/nginx/logs"
oldlogs_path="/nginx_oldlogs/"

for i in `ls $logs_path/* |grep -v nginx.pid |grep -v oldlogs`
        do
        mv "$i"  "$i"_${HOS}_$(date -d "yesterday" +"%Y%m%d")
        mv "$i"_${HOS}_$(date -d "yesterday" +"%Y%m%d")  $oldlogs_path
done

#向nginx主進程發信號重新打開日誌
nginx_pid= `ps -ef |grep nginx|grep master|awk '{print $1}'`
kill -USR1 $nginx_pid
/usr/local/nginx/sbin/nginx -t && /usr/local/nginx/sbin/nginx -s reload

sleep 2
#docker exec -it tengine  /usr/local/nginx/sbin/nginx -s reopen

#sleep 1 

#clear the expired logs
cd $oldlogs_path
#find ./ -mtime +90 -exec rm -rf {} \;
echo "The old logfiles is deleted!!"

思路:

對日誌進行管理,結合cron每天進行切割,
1.定義日誌的位置,及存儲的位置。
2.對日誌進行重新命名 移動到指定的位置
3.向nginx主進程發信號重新打開日誌
4.對舊的日誌進行刪除處理

6.msqyl 主從監控

#!/bin/bash 
USER=bak 
PASSWD=123456 
IO_SQL_STATUS=$(mysql -u$USER -p$PASSWD -e 'show slave status\G' |awk -F: '/Slave_.*_Running/{gsub(": ",":");print $0}') #gsub去除冒號後面的空格 
for i in $IO_SQL_STATUS; do 
	THREAD_STATUS_NAME=${i%:*} 
	THREAD_STATUS=${i#*:} 
	if [ "$THREAD_STATUS" != "Yes" ]; then 
		echo "Error: MySQL Master-Slave $THREAD_STATUS_NAME status is 
$THREAD_STATUS!" 
	fi 
done

7.expect實現ssh 免密登錄

#!/usr/bin/expect
spawn ssh [email protected]
set timeout 10   //設置超時時間
expect "*password:"
send "nbc@123\r" //輸入密碼
expect { 
	"*yes/no" { send "yes\r"; exp_continue}  //第一次ssh連接會提示yes/no,繼續 
	 "*password:" { send "$password\r" }  //出現密碼提示,發送密碼
} 
interact //交互模式,用戶會停留在遠程服務器上面.
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章