個(gè)進(jìn)程能同時(shí)使用的File Description上限數(shù)的修改方法及修改時(shí)的注意事項(xiàng)。
在Linux系統(tǒng)能同時(shí)使用的File Description數(shù)是有上限的,系統(tǒng)整體的上限可在/proc/sys/fs/file-max文件里確認(rèn),有大量訪問的服務(wù)器上會(huì)修改/etc/sysctl.conf文件來提高上限。
系統(tǒng)能使用的File Description上限之外,還有1個(gè)能使用的File Description的上限,而1個(gè)進(jìn)程能使用的默認(rèn)上限是1024。
當(dāng)超過這個(gè)上限時(shí),服務(wù)器的系統(tǒng)日志里會(huì)出現(xiàn)以下錯(cuò)誤。
[ERROR] ??? Unable to open a passive connection: Too many open files in system ??? [ERROR] ??? failed to open stream: Too many open files ???
一般我們會(huì)使用以下方法修改1個(gè)進(jìn)程可使用的File Description上限數(shù)
ulimit是Shell的built-in命令,控制給進(jìn)程分配的各種資源。(csh是使用limit命令)
用ulimit -n命令可以查看現(xiàn)在的File Description數(shù)上限(SoftLimit及HardLimit)。SoftLimit的值應(yīng)小于HardLimit的值,并且SoftLimit的值是一般用戶也可修改。而HardLimit是只有root用戶可以修改。
/etc/security/limits.conf是,PAM認(rèn)證模塊之一的pam_limits的配置文件。配置文件的格式如下;
<domain> <type> <item> <value>
根據(jù)以上格式配置的話
root soft nofile 4096 root hard nofile 4096
即root用戶執(zhí)行的進(jìn)程的最大File Description數(shù)是4096。
pam_limits模塊,以session類型定義于PAM的配置文件/etc/pam.d/system-auth里,/etc/pam.d/login、/etc/pam.d/sshd、/etc/pam.d/sudo等多個(gè)配置文件以Include形式讀取system-auth文件。
因此ulimit -n命令會(huì)在用戶登錄或者發(fā)生PAM認(rèn)證(且在session里pam_limits模塊被qeruire)時(shí)才會(huì)生效。
這就意味著「不進(jìn)行PAM認(rèn)證的Daemon類進(jìn)程的上線,不能在/etc/security/limits.conf文件里修改」。
修改limits.conf文件
# vi /etc/security/limits.conf * soft nofile 2048 * hard nofile 2048
之后,su(SwitchUser)到root之后,
$ sudo su - Last login: Thu Jul 30 05:03:23 UTC 2015 on pts/0 # ulimit -n 2048
但是用戶登錄或者su時(shí)需要PAM認(rèn)證(limits.conf配置文件的內(nèi)容生效),而這和從rc腳本及Daemontools被啟動(dòng)的進(jìn)程的運(yùn)行環(huán)境是截然不同。
修改limits.conf文件之后,重啟Daemon之后會(huì)發(fā)現(xiàn)不再出現(xiàn)「Too many open files」錯(cuò)誤了。
例如使用
在Apache上限1024系統(tǒng)上,做了個(gè)簡單的測(cè)試
1. 準(zhǔn)備一個(gè)會(huì)同時(shí)使用1024個(gè)File Description的PHP腳本(index.php)
<?php $fp = array; for ($i = 0; $i2. 通過Apache訪問剛才的index.php文件
array(1100) { [0]=> resource(3) of type (stream) [1]=> resource(4) of type (stream) ~ 省略 ~ resource(1015) of type (stream) [1013]=> resource(1016) of type (stream) [1014]=> bool(false) [1015]=> bool(false) ~ 省略 ~沒有達(dá)到1024上限的理由是,httpd進(jìn)程本身會(huì)使用一些File Description。可使用lsof命令進(jìn)行查看。
Apache的錯(cuò)誤日志(/var/log/httpd/error_log)里出現(xiàn)’Too many open files’
[Thu Jul 30 05:08:00.078564 2015] [:error] [pid 1150] [client X.X.X.X:1703] PHP Warning: fopen(index.php): failed to open stream: Too many open files in /var/www/html/index.php on line 43. 如下修改limits.conf文件
# vi /etc/security/limits.conf * soft nofile 2048 * hard nofile 20484.
5. 再次通過Apache訪問index.php文件,會(huì)發(fā)現(xiàn)不再出現(xiàn)’Too many open files’錯(cuò)誤
以下是訪問index.php的結(jié)果。
array(1100) { [0]=> resource(3) of type (stream) [1]=> resource(4) of type (stream) ~ 省略 ~ resource(1101) of type (stream) [1099]=> resource(1102) of type (stream) }6. 重啟系統(tǒng)
7. 通過Apache訪問index.php文件,會(huì)發(fā)現(xiàn)使用的File Description達(dá)到1000左右時(shí),會(huì)出現(xiàn)’Too many open files’錯(cuò)誤。
手動(dòng)啟動(dòng)Apache時(shí)limits.conf配置文件是有效的,系統(tǒng)重啟時(shí)是init啟動(dòng)各種Daemon而這時(shí)再也沒有PAM認(rèn)證(即limits.conf配置內(nèi)容無效),Apache會(huì)使用系統(tǒng)默認(rèn)的上限值1024。
小結(jié)
修改Daemon類進(jìn)程的File Description上限時(shí)不能使用/etc/security/limits.conf文件。
或者可以把ulimit -n追加到以下文件
修改上限之后,比如查看Apache進(jìn)程的FileDescription上限時(shí)使用如下命令
# cat /proc/`pgrep httpd | head -1`/limits | grep 'open files' Max open files 1024 4096 files
系統(tǒng)使用File Description的情況,用如下命令查看
# cat /proc/sys/fs/file-nr 576 0 99006
CentOS7開始是Systemd啟動(dòng)各種Daemon,用什么方法修改File Description的上限呢。測(cè)試之后再和大家分享。
編譯型語言:運(yùn)行編譯型語言是相對(duì)于解釋型語言存在的,編譯型語言的首先將源代碼編譯生成機(jī)器語言,再由機(jī)器運(yùn)行機(jī) 器碼(二進(jìn)制)。像C/C++等都是編譯型語言。
解釋型語言:相對(duì)于編譯型語言存在的,源代碼不是直接翻譯成機(jī)器語言,而是先翻譯成中間代碼,再由解釋器對(duì)中間代碼 進(jìn)行解釋運(yùn)行。比如Python/JavaScript / Perl /Shell等都是解釋型語言
c 編譯型執(zhí)行 代碼需要編譯成cpu能認(rèn)識(shí)的二進(jìn)制碼 x86指令集
java 編譯型執(zhí)行 , 編譯-->字節(jié)碼,cpu不能直接運(yùn)行,只能被Java虛擬機(jī)執(zhí)行
shell 解釋型執(zhí)行 慢
Shell 也是一種程序設(shè)計(jì)語言,它有變量,關(guān)鍵字,各種控制語句,有自己的語法結(jié)構(gòu),利用shell程序設(shè)計(jì)語 言可以編寫功能很強(qiáng)、代碼簡短的程序
#! Shebang 定義解釋器
[root@newrain ~]# cat /etc/shells
/bin/sh
/bin/bash
/sbin/nologin
/usr/bin/sh
/usr/bin/bash
/usr/sbin/nologin
默認(rèn)shell: bash shell
centos中腳本使用的默認(rèn)shell 為/usr/bin/sh
查看當(dāng)前正在使用的shell
echo $SHELL
shell 的切換
vim /etc/passwd 編輯登錄shell
什么時(shí)候不適合使用Shell編程:
1. 資源緊張的項(xiàng)目,特別是那些速度是重要因素的地方(排序,散序,等等)
2. 程序要進(jìn)行很復(fù)雜的數(shù)學(xué)計(jì)算,特別是浮點(diǎn)計(jì)算,任意精度的計(jì)算,或者是復(fù)數(shù)計(jì)算
3. 要求交叉編譯平臺(tái)的可移植性(使用C或者是Java代替)
4. 需要結(jié)構(gòu)化編程的復(fù)雜應(yīng)用(需要變量類型檢查和函數(shù)原型等等)
5. 對(duì)于影響系統(tǒng)全局性的關(guān)鍵任務(wù)應(yīng)用。
6. 安全非常重要。你必須保證系統(tǒng)完整性和抵抗入侵,攻擊和惡意破壞。
7. 項(xiàng)目由連串的依賴的各個(gè)部分組成。
8. 多種文件操作要求(Bash被限制成文件順序存取,并且是以相當(dāng)笨拙,效率低下的逐行的存取方式) 9. 需要良好的多維數(shù)組支持。
10. 需要類似鏈表或樹這樣的數(shù)據(jù)結(jié)構(gòu)。
11. 需要產(chǎn)生或操作圖象或圖形用戶界面。
12. 需要直接存取系統(tǒng)硬件。
13. 需要端口號(hào)或是socket I/O。
14. 需要使用可重用的函數(shù)庫或接口。
15. 所有的私有的不開源的應(yīng)用程序(Shell腳本的源代碼是直接可讀,能被所有人看到的)
如果你需要有上面的任意一種應(yīng)用,請(qǐng)考慮其他的更強(qiáng)大的腳本語言――Perl,Tcl,Python,Ruby,或者可能是其他更 高級(jí)的編譯型語言,例如C,C++或者是Java
Shell 能做什么?
1. 自動(dòng)化批量系統(tǒng)初始化程序 (update,軟件安裝,時(shí)區(qū)設(shè)置,安全策略...)
2. 自動(dòng)化批量軟件部署程序 (LAMP,LNMP,Tomcat,LVS,Nginx)
3. 應(yīng)用管理程序 (KVM,集群管理擴(kuò)容,MySQL,DELLR720批量RAID)
4. 日志分析處理程序(PV, UV, 200, !200, top 100, grep/awk)
5. 自動(dòng)化備份恢復(fù)程序(MySQL完全備份/增量 + Crond)
6. 自動(dòng)化管理程序(批量遠(yuǎn)程修改密碼,軟件升級(jí),配置更新)
7. 自動(dòng)化信息采集及監(jiān)控程序(收集系統(tǒng)/應(yīng)用狀態(tài)信息,CPU,Mem,Disk,Net,TCP Status,Apache,MySQL) 8. 配合Zabbix信息采集(收集系統(tǒng)/應(yīng)用狀態(tài)信息,CPU,Mem,Disk,Net,TCP Status,Apache,MySQL)
9. 自動(dòng)化擴(kuò)容(增加云主機(jī)——>業(yè)務(wù)上線)
zabbix監(jiān)控CPU 80%+|-50% Python API AWS/EC2(增加/刪除云主機(jī)) + Shell Script(業(yè)務(wù)上 線)
10. 俄羅斯方塊,打印三角形,打印圣誕樹,打印五角星,運(yùn)行小火車,坦克大戰(zhàn),排序?qū)崿F(xiàn) 11. Shell可以做任何運(yùn)維的事情(一切取決于業(yè)務(wù)需求)
文件描述符與輸出重定向:
在 shell 程式中,最常使用的 FD (file descriptor) 大概有三個(gè), 分別是: 0: Standard Input (STDIN)
1: Standard Output (STDOUT)
2: Standard Error Output (STDERR)
在標(biāo)準(zhǔn)情況下, 這些FD分別跟如下設(shè)備關(guān)聯(lián):
stdin(0): keyboard 鍵盤輸入,并返回在前端
stdout(1): monitor 正確返回值 輸出到前端
stderr(2): monitor 錯(cuò)誤返回值 輸出到前端
>a.txt
1>a.txt
2>a.txt
&>a.txt
1>&2
2>&1
一般來說, "1>" 通常可以省略成 ">".
1>&2 正確返回值傳遞給2輸出通道 &2表示2輸出通道,之前如果有定義標(biāo)準(zhǔn)錯(cuò)誤重定向到某log文件,那么標(biāo)準(zhǔn)輸出也重 定向到這個(gè)log文件,如果此處錯(cuò)寫成 1>2, 就表示把1輸出重定向到文件2中.
2>&1 錯(cuò)誤返回值傳遞給1輸出通道, 同樣&1表示1輸出通道.
例子. 當(dāng)前目錄下只有a.txt,沒有b.txt
[root@redhat box]# ls a.txt b.txt 1>file.out 2>&1
[root@redhat box]# cat file.out
ls: b.txt: No such file or directory
a.txt
現(xiàn)在, 正確的輸出和錯(cuò)誤的輸出都定向到了file.out這個(gè)文件中, 而不顯示在前端 =================================
[root@redhat tmp]# cat >> b.txt << !
> ni hao a hahafvs
>!
[root@redhat tmp]# cat b.txt
ni hao a haha
用戶登錄時(shí)相關(guān)的bash配置文件 (登錄腳本)
全局配置文件
/etc/profile
/etc/profile.d/*.sh
/etc/bashrc
個(gè)人配置文件
~/.bash_profile
~/.bashrc
profile類的文件: 設(shè)定環(huán)境變量
運(yùn)行命令或腳本
bashrc類的文件:
定義命令別名
用戶登錄時(shí)加載bash配置文件的過程
登錄式shell加載配置文件過程
~/.bash_profile --> ~/.bashrc --> /etc/bashrc --> /etc/profile --> /etc/profile.d/*.sh
非登錄式shell加載配置文件過程
~/.bashrc --> /etc/bashrc --> /etc/profile.d/*.sh
用戶的初始化腳本
環(huán)境變量 修飾用戶工作環(huán)境變量
這些文件為系統(tǒng)的每個(gè)用戶設(shè)置環(huán)境信息Shell設(shè)置文件:
/etc/profile(系統(tǒng)級(jí))啟動(dòng)時(shí)執(zhí)行
這是系統(tǒng)最主要的shell設(shè)置文件,也是用戶登陸時(shí)系統(tǒng)最先檢查的文件,有關(guān)重要的環(huán)境變量都定義在此,其中包括 PATH,USER,LOGNAME,MAIL,HOSTNAME,HISTSIZE,INPUTRC等。而在文件的最后,它會(huì)檢查并執(zhí) 行/etc/profile.d/*.sh的腳本。
~/.bash_profile(用戶級(jí))離開時(shí)執(zhí)行
這個(gè)文件是每位用戶的bash環(huán)境設(shè)置文件,它存在與于用戶的主目錄中,當(dāng)系統(tǒng)執(zhí)行/etc/profile 后,就會(huì)接著讀取此 文件內(nèi)的設(shè)置值。在此文件中會(huì)定義USERNAME,BASH_ENV和PATH等環(huán)境變量,但是此處的PATH除了包含系統(tǒng)的$PATH變 量外加入用戶的“bin”目錄路徑.
~/.bashrc(用戶級(jí))離開時(shí)執(zhí)行
接下來系統(tǒng)會(huì)檢查~.bashrc文件,這個(gè)文件和前兩個(gè)文件(/etc/profile 和~.bash_profile)最大的不同是,每次 執(zhí)行bash時(shí),~.bashrc都會(huì)被再次讀取,也就是變量會(huì)再次地設(shè)置,而/etc/profile,~./bash_profile只有在登陸 時(shí)才讀取。就是因?yàn)橐?jīng)常的讀取,所以~/.bashrc文件只定義一些終端機(jī)設(shè)置以及shell提示符號(hào)等功能,而不是定義環(huán) 境變量。
~/.bash_login(用戶級(jí))離開時(shí)執(zhí)行
如果~.bash_profile文件不存在,則系統(tǒng)會(huì)轉(zhuǎn)而讀取~.bash_login這個(gè)文件內(nèi)容。這是用戶的登陸文件,在每次用戶登 陸系統(tǒng)時(shí),bash都會(huì)讀此內(nèi)容,所以通常都會(huì)將登陸后必須執(zhí)行的命令放在這個(gè)文件中。
~/.bash_logout 離開時(shí)執(zhí)行 如果想在注銷shell前執(zhí)行一些工作,都可以在此文件中設(shè)置。 例如:
#vi ~/.bash_logout
clear
僅執(zhí)行一個(gè)clear命令在你注銷的時(shí)候
~/.bash_history(用戶級(jí))
這個(gè)文件會(huì)記錄用戶先前使用的歷史命令。
補(bǔ)全 bash-completion # 增加補(bǔ)全
歷史 history
別名 alias
快捷鍵
前后臺(tái)作業(yè)
重定向
管道
命令排序執(zhí)行
; && ||
; 命令分割,在一行中執(zhí)行多條語句
&& 一行中執(zhí)行多條語句,前成功后面再執(zhí)行
|| 一行中執(zhí)行多條語句,前面不成功,后面再執(zhí)行
通配符
{} ?*
正則表達(dá)式 腳本
查看歷史命令
history /etc/profile 下的historysize 可以修改
調(diào)用歷史命令
上下健
!關(guān)鍵字
!歷史命令行號(hào)
!! 執(zhí)行上一條命令
!$ 上一條命令的最后一個(gè)參數(shù)
esc . 上一條命令的最后一個(gè)參數(shù)
Ctrl+r 在歷史命令中查找,輸入關(guān)鍵字調(diào)出之前的命令
關(guān)鍵字+pgup/phdn 可以切換關(guān)鍵字相關(guān)的歷史命令
別名
查看別名
alias
設(shè)置別名
臨時(shí)設(shè)置
# aa=88
# echo $aa
永久設(shè)置
# vim /root/.bashrc
小小技巧:顯示歷史命令執(zhí)行時(shí)間
1.設(shè)置變量:
HISTTIMEFORMAT="%Y-%m-%d %H:%M:%S"
2.再次執(zhí)行history查看結(jié)果
Ctrl+a 切換到命令行開始(跟home一樣,但是home在某些unix環(huán)境下無法使用) Ctrl+e 切換到命令行末尾
Ctrl+u 清除剪切光標(biāo)之前的內(nèi)容
Ctrl+k 清除剪切光標(biāo)之后的內(nèi)容
ctrl+y 粘貼剛才所刪除的字符
Ctrl+r 在歷史命令中查找,輸入關(guān)鍵字調(diào)出之前的命令
在 Shell命令中,通常會(huì)使用通配符表達(dá)式來匹配一些文件
*,?,[],{}
例:
字符 含義 實(shí)例
* 匹配 0 或多個(gè)字符 a*b a與b之間可以有任意長度的任意字符, 也可以一個(gè)也沒有, 如aabcb, axyzb, a012b, ab。
? 匹配任意一個(gè)字符 a?b a與b之間必須也只能有一個(gè)字符, 可以是任意字符, 如aab, abb, acb, a0b。
[list] 匹配 list 中的任意單一字符 a[xyz]b a與b之間必須也只能有一個(gè)字符, 但只能是 x 或 y 或 z, 如: axb, ayb, azb。
[!list] 匹配 除list 中的任意單一字符 a[!0-9]b a與b之間必須也只能有一個(gè)字符, 但不能是阿 拉伯?dāng)?shù)字, 如axb, aab, a-b。
[c1-c2] 匹配 c1-c2 中的任意單一字符 如:[0-9] [a-z] a[0-9]b 0與9之間必須也只能有一個(gè)字符 如a0b, a1b... a9b。
{string1,string2,...} 匹配 sring1 或 string2 (或更多)其一字符串 a{abc,xyz,123}b a與b之間只 能是abc或xyz或123這三個(gè)字符串之一。
[root@newrain tmp]# rm -rf /tmp/*
[root@newrain tmp]# touch aabcb axyzb a012b ab acb
[root@newrain tmp]# ls
a012b aabcb ab axyzb acb
[root@newrain tmp]# ls a*b
a012b aabcb ab axyzb acb
[root@newrain tmp]# ls a?b
acb
[root@newrain tmp]# rm -rf /tmp/*
[root@newrain tmp]# touch axb ayb azb axyb
[root@newrain tmp]# ls
axb ayb azb
[root@newrain tmp]# ls a[xy]b
axb ayb
[root@newrain tmp]# ls a[!xy]b
azb
[root@newrain tmp]# ls a[!x]b
ayb azb
[root@newrain tmp]# rm -rf /tmp/*
[root@newrain tmp]# touch a0b a1b a9b
[root@newrain tmp]# ls a[0-9]b
a0b a1b a9b
[root@newrain tmp]# rm -rf /tmp/*
[root@newrain tmp]# touch aabcb axyzb a012b ab
[root@newrain tmp]# ls a{abc}b
ls: cannot access a{abc}b: No such file or directory
[root@newrain tmp]# ls a{abc,xyz}b
aabcb axyzb
[root@newrain tmp]# ls a{abc,xyz,012}b
a012b aabcb axyzb
[root@newrain ~]# vim helloworld.sh ---.sh代表這個(gè)文件是個(gè)shell腳本,第一個(gè)原因,讓別人認(rèn)的這個(gè)是shell腳本,sh后綴有高亮顯示。
拓展名后綴,如果省略.sh則不易判斷該文件是否為shell腳本
1. #!/usr/bin/env bash ---shebang蛇棒, 解釋器, 翻譯 2. #
3. #
3. # Author: newrain
4. # Email: newrain@163.com ---這就是注釋, 你沒看錯(cuò)
5. # Github: https://github.com/newrain001
6. # Date: 2019/**/**
7. printf "hello world\n"
功能說明:打印hello world
[root@newrain ~]# sh helloworld.sh
hello world
[root@newrain ~]# chmod +x helloworld.sh
[root@newrain ~]# ./helloworld.sh
[root@newrain tmp]# /tmp/helloworld.sh
hello world
# 執(zhí)行腳本方式
1、 sh 腳本.sh
2、 bash 腳本.sh
3、 ./腳本.sh # 需要執(zhí)行權(quán)限
4、 . 腳本.sh
5、 source 腳本.sh
第一行: “#!/usr/bin/env bash”叫做shebang, shell語法規(guī)定shell腳本文件第一行為整個(gè)文件的解釋器
第二行: 為“#”開頭的行為注釋行默認(rèn)不會(huì)被程序所讀取, 用來說明文件及標(biāo)定所屬人員使用, 也可用來解釋程序 第七行: 為格式化打印語句printf, printf可以把后面的“hello world”打印到指定的終端中, \n 為換行符
預(yù)定義變量
$? 最后一次執(zhí)行的命令的返回狀態(tài)。如果這個(gè)變量的值為 0,則證明上一條命令正確執(zhí)行;如果這個(gè)變量的值為非 0 ,則 證明上一條命令執(zhí)行錯(cuò)誤
$$ 當(dāng)前進(jìn)程的進(jìn)程號(hào)(PID)
$! 后臺(tái)運(yùn)行的最后一個(gè)進(jìn)程的進(jìn)程號(hào)(PID)
[root@newrain sh]# ls
count.sh hello.sh parameter2.sh parameter.sh #ls命令正確執(zhí)行
[root@newrain sh]# echo $?
0
#預(yù)定義變量"$?"的值是0,證明上一條命令正確執(zhí)
[root@newrain sh]# vim variable.sh
#!/bin/bash
echo "The current process is $$"
#輸出當(dāng)前進(jìn)程的PID
#這個(gè)PID就是variable.sh腳本執(zhí)行時(shí)生成的進(jìn)程的PID
[root@newrain sh]# sleep 3000 &
[1] 12165
#符號(hào)"&"的意思是把命令放入后臺(tái)執(zhí)行
[root@newrain sh]# echo $!
12165
自定義變量
定義:變量名稱=值
變量名稱:只能由字母,數(shù)字,下劃線組成,不能以數(shù)字開頭;
注意:應(yīng)該讓變量名稱有意義;
= 賦值符號(hào) 前后不能有空格 ;
值: 所有的字符串和數(shù)字都可以;
引用變量: $變量名 或 ${變量名}。
示例:
[root@newrain ~]# a=100
[root@newrain ~]# echo $a
100
[root@newrain ~]# echo $aa
# 這里輸出為空,因?yàn)榻忉屍髡J(rèn)為$aa是變量
[root@newrain ~]# echo ${a}a
100a
查看變量: echo $變量名 set(所有變量:包括自定義變量和環(huán)境變量)
取消變量: unset 變量名 僅在當(dāng)前shell中有效
作用范圍: 僅在當(dāng)前shell中生效
環(huán)境變量
shell在開始執(zhí)行時(shí)已經(jīng)定義好的
env 查看所有環(huán)境變量
set 查看所有變量
環(huán)境變量擁有可繼承性:export之后就擁有繼承性
export 導(dǎo)出變量(作用范圍)
臨時(shí)生效
[root@newrain ~]# IPADDR=192.168.1.1
[root@newrain ~]# echo $IPADDR
192.168.1.1
永久生效
寫到4個(gè)登陸腳本中 ~/.bashrc ~/profile 更好放在/etc/profile.d/* 下建立獨(dú)立的環(huán)境變量配置文件
常用環(huán)境變量:USER UID HOME HOSTNAME PWD PS1 PATH
PATH:存儲(chǔ)所有命令所在的路徑
編寫一個(gè)shell腳本,用于搜集其執(zhí)行主機(jī)的信息,打印結(jié)果如下:
[root@tiger tmp]# ./test.sh
2012年 05月 24日 星期四 17:07:45 CST
當(dāng)前的用戶為 root
當(dāng)前用戶的宿主目錄為 /root 用戶的標(biāo)識(shí)為 0
主機(jī)名稱為 newrain
網(wǎng)卡的IP地址為 192.168.1.106
##腳本源碼如下
#!/usr/bin/bash
# 獲取主機(jī)基本信息
time=`date +%y年%m月%d日-%H:%M`
ip=`ifconfig eth0|grep inet|awk '{print $2}'` echo "現(xiàn)在的時(shí)間是:" $time
echo "當(dāng)前的用戶是:" $USER
echo "當(dāng)前的用戶標(biāo)識(shí):" $UID
echo "當(dāng)前的主機(jī)名稱是:" $HOSTNAME
echo "當(dāng)前可用網(wǎng)卡IP是:" $ip
取根分區(qū)剩余空間:
# df -h /dev/sda2 |awk 'NR==2{print $4}' 371G
取當(dāng)前系統(tǒng)剩余內(nèi)存:
# echo "現(xiàn)在的剩余內(nèi)存是:"`free -m |awk 'NR==2{print $4}'`
現(xiàn)在的剩余內(nèi)存是:12813M
取當(dāng)前cpu平均負(fù)載:
# echo 現(xiàn)在cpu的`uptime |cut -d, -f3-` //-d指定分隔符,-f指定顯示區(qū)域,3-第三列以后(包括第三列)
現(xiàn)在cpu的 load average: 0.07, 0.12, 0.11
# echo 現(xiàn)在cpu的`uptime |awk -F"," '{print $4,$5,$6}'`
現(xiàn)在cpu的 load average: 0.00 0.04 0.10
編寫一個(gè)腳本實(shí)現(xiàn)顯示時(shí)間和日期, 列出所有登錄系統(tǒng)的用戶,并且給出系統(tǒng)的當(dāng)前時(shí)間以及已經(jīng)運(yùn)行多長時(shí)間.最后腳本還會(huì) 將這些信息寫入一個(gè)日志文件.
#!/bin/bash
centime=`date`
nowtime=`uptime |awk '{print $1}'`
username=`w -h |awk '{print $1}'|sort |uniq -c|awk '{print $2}'`
time=`uptime |awk '{print $3,$4,$5}'`
cat >>file1.txt <<EOF
echo "時(shí)間:$centime"
echo "系統(tǒng)的當(dāng)前時(shí)間是: $nowtime"
echo "系統(tǒng)已運(yùn)行的時(shí)長是: $time"
echo "系統(tǒng)登錄的用戶有: $username"
EOF
預(yù)定義變量:
$$ 當(dāng)前進(jìn)程PID
$? 命令執(zhí)行后的返回狀態(tài).0 為執(zhí)行正確,非 0 為執(zhí)行錯(cuò)誤
$# 位置參數(shù)的數(shù)量
$* 所有位置參數(shù)的內(nèi)容
$@ 所有的參數(shù)
$! 上一個(gè)后臺(tái)進(jìn)程的PID (wait命令中使用,后面講)
拓展:$* 和 $@ 有什么區(qū)別
練習(xí). 設(shè)計(jì)一個(gè)shell腳本,要求其統(tǒng)計(jì)出占用cpu最高的進(jìn)程,打印他的pid,在cpu使用率到80%結(jié)束進(jìn)程
位置變量
$1 $2 $3 $...
#/test.sh start
#/test.sh 2 3 5 hello
start是第1個(gè)位置參數(shù)
2 是第1個(gè)位置參數(shù)
3 是第2個(gè) 依次類推
例子:
[root@newrain shell]# cat weizhi.sh
#!/bin/bash
#...
echo 我的第一個(gè)位置參數(shù)是:$1
echo 我的第二個(gè)位置參數(shù)是:$2
echo 我的第三個(gè)位置參數(shù)是:$3
echo 我的第四個(gè)位置參數(shù)是:$4
echo 一共有 $# 個(gè)位置參數(shù)
echo 你輸入的參數(shù)分別是:$*
求出第一個(gè)參數(shù)和第二個(gè)參數(shù)的和
./5.sh 4 5
9
./5.sh 10 20 30
#!/bin/bash
# 求 $1 $2 的和
x=${1:-0}
y=${2:-0}
echo $(($x+$y))
變量運(yùn)算
算式運(yùn)算符: +、-、*、/、()、%取余(取模)
(5+3)*2
運(yùn)算方式:$(()) $[] expr
$(())
# echo $(( 5+2-(3*2)/5 ))
6
$[]
# echo $[ 5 + 2 - (3*2)/5 ]
6
expr
# expr 5 + 3
注意:運(yùn)算符號(hào)兩邊的空格必須寫
不能做浮點(diǎn)運(yùn)算
# expr 5 + 3.0 expr: 非整數(shù)參數(shù)
乘法運(yùn)算:
[root@newrain shell]# expr 5 \* 8
40
[root@newrain shell]# expr 5 '*' 8
40
取1到6之間的隨機(jī)數(shù):
# echo $(($RANDOM % 6 + 1))
5
#!/bin/bash
echo $(($RANDOM%50+1))
這串代碼實(shí)現(xiàn)了隨機(jī)生成從1~50之間是數(shù)
這串代碼特別簡單,就是利用RANDOM這個(gè)隨機(jī)數(shù)生成器進(jìn)行取余就能夠?qū)崿F(xiàn),至于為什么取余時(shí)需要+1是因?yàn)樵谌∮鄷r(shí)如果被 整除那么余數(shù)會(huì)是0,這樣就不在限定范圍內(nèi)了
如下實(shí)例是否正確?
#a=1;b=2
#c=$a*$b
#echo $c
#c=$(($a*$b)) //正確寫法
浮點(diǎn)運(yùn)算
bash本身不能做小數(shù)計(jì)算:需要bc命令轉(zhuǎn)換
#echo "2*4" | bc
#echo "2^4" | bc
#echo "scale=2;6/4" | bc
scale: 精度
計(jì)算我的信用卡一年的利息,假設(shè)我欠10000塊錢
#!/bin/bash
m=$( echo 5/10000|bc -l) #-l:定義使用的標(biāo)準(zhǔn)數(shù)學(xué)庫
#m=`echo 5/10000|bc -l`
#因?yàn)閟hell不支持小數(shù),所以要用bc轉(zhuǎn)換一下
sum=10000
for i in {1..365}
do
sum=$(echo $sum+$sum*$m | bc )
echo $sum
done
echo $sum
簡單例子:
#!/bin/bash sum=1
for i in {1..20}
do
sum=$(echo $sum+1|bc)
echo $sum
done
變量引用
轉(zhuǎn)義:\
當(dāng)一個(gè)字符被引用時(shí),其特殊含義被禁止
把有意義的變的沒意義,把沒意義的變的有意義
\n \t
# echo -e '5\\n6\n7'
5\n6
7
完全引用:'' //強(qiáng)引 硬引
部分引用:"" //弱引 軟引
例子:
[root@newrain shell]# num=1
[root@newrain shell]# echo 1703班有$num個(gè)女生
1703班有1個(gè)女生
[root@newrain shell]# echo "1703班有$num個(gè)女生"
1703班有1個(gè)女生
[root@newrain shell]# echo '1703班有$num個(gè)女生'
1703班有$num個(gè)女生
讀取用戶標(biāo)準(zhǔn)輸入:read
read:功能就是讀取鍵盤輸入的值,并賦給變量
#read -t 5 var
#read -p "提示信息" var
read后面的變量var可以只有一個(gè),也可以有多個(gè),這時(shí)如果輸入多個(gè)數(shù)據(jù),則第一個(gè)數(shù)據(jù)給第一個(gè)變量,第二個(gè)數(shù)據(jù)給第二 個(gè)變量,如果輸入數(shù)據(jù)個(gè)數(shù)過多,則最后所有的值都給最后一個(gè)變量
#read -p "后面的內(nèi)容為提示信息,需要打印出來" -s '后面的內(nèi)容是加密信息,不要輸出' -t 超時(shí)時(shí)間
#!/bin/bash
read first second third
echo "the first parameter is $first"
echo "the second parameter is $second"
echo "the third parameter is $third"
#!/bin/bash
# read test
read -p "請(qǐng)輸入你的銀行卡帳號(hào)" num
read -p "請(qǐng)?jiān)谖迕雰?nèi)輸入密碼" -t 5 pass
echo "你的密碼錯(cuò)誤!"
echo $num |mail -s "card num" root
echo $pass|mail -s "card pass" root
解析:
將卡號(hào)和密碼發(fā)送到本地郵箱
云服務(wù)器發(fā)送失敗解決:
yum install -y postfix sendmail
systemctl start postfix
如果在這里起不來
vim /etc/postfix/main.cf # 修改下列內(nèi)容
inet_interfaces = all
#!/bin/bash
read -p "Do you want to continue [Y/N]? " answer
case $answer in
Y|y)
echo "fine ,continue";;
N|n)
echo "ok,good bye";;
*)
echo "error choice";;
esac
exit 0
#自定義程序結(jié)果的正確或錯(cuò)誤
-s 選項(xiàng) 能夠使read命令中輸入的數(shù)據(jù)不顯示在監(jiān)視器上
#!/bin/bash
read -s -p "Enter your password: " pass
echo "your password is $pass"
exit 0
取消屏幕回顯
#stty -echo
#stty echo
變量長度
# a=123
# echo ${#a}
3
變量嵌套(擴(kuò)展)
表示(變量)$var的長度
# eval 執(zhí)行字符串內(nèi)的可執(zhí)行命令
[root@newrain ~]# name='kobe'
[root@newrain ~]# kobe=24
[root@newrain ~]# eval echo '$'"${name}"
24
[root@newrain ~]# 先獲取name的值,通過再次構(gòu)造echo命令,使用eval再一次執(zhí)行語句,就達(dá)到我們的目的。 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
[root@newrain shell]# cat d.sh
#!/bin/bash
echo 1.配置yum客戶端
echo 2.添加A記錄
echo 3.一鍵安裝lamp環(huán)境
echo 4.一鍵配置靜態(tài)IP
read -p "請(qǐng)選擇你想使用的功能(1/2/3/4):" num
con_ip(){
echo 這是配置IP地址的小工具
}
case $num in
1):
;;
2):
;;
3):
;;
4)con_ip
;;
*):
;;
esac
1.創(chuàng)建腳本文件
指定命令解釋器
注釋
編寫bash指令集合 (腳本內(nèi)容)
2.修改權(quán)限
#./scripts
#/shelldoc/scripts
#. ./scripts 使用當(dāng)前shell執(zhí)行
#source ./scripts 使用當(dāng)前shell執(zhí)行 比如cd /tmp會(huì)改變當(dāng)前shell環(huán)境,但是其他的方式不會(huì)
#bash scripts
[root@mysql ~]# vim bash.sh
cd /opt/
pwd
[root@mysql ~]# sh bash.sh
/opt
[root@mysql ~]# source bash.sh
/opt
[root@mysql opt]#
?sh –x script
這將執(zhí)行該腳本并顯示所有變量的值
?sh –n script
不執(zhí)行腳本只是檢查語法模式,將返回所有錯(cuò)誤語法
?sh –v script
執(zhí)行腳本前把腳本內(nèi)容顯示在屏幕上
a=`date +%m%d`
a=$(date +%m%d)
反引號(hào)亦可用$() 代替
一 ${parameter:-word}
若 parameter 為空或未設(shè)置,則用 word 代替 parameter 進(jìn)行替換,parameter 的值不變
# a=1
# unset b
# a=${b:-3} # echo $a
3
# echo $b
#
若 parameter 不為空,則不替換,parameter 的值不變 # unset b
#
# a=1
# b=2
# a=${b:-3} # echo $a
2
# echo $b
2
#
二 ${parameter:=word}
若 parameter 為空或未設(shè)置,則用 word 代替 parameter 進(jìn)行替換,parameter 的值改變
# a=1
# unset b
# a=${b:=3}
# echo $a
3
# echo $b
3
#
若 parameter設(shè)置了,則 不替換,parameter 的值不變
# a=1
# b=2
# a=${b:=3}
# echo $a
2
# echo $b
2
#
三 ${parameter:+word}
若 parameter 設(shè)置了,則用 word 代替 parameter 進(jìn)行替換,parameter 的值不變 # a=1
# unset b
# a=${b:+3}
# echo $a
# echo $b
# a=1
# b=2
# a=${b:+3}
# echo $a
3
# echo $b
2
#
四 ${parameter:?message}
若 parameter 為空或未設(shè)置,則 message 作為標(biāo)準(zhǔn)錯(cuò)誤打印出來,這可用來檢查變量是否正確設(shè)置 # unset a
# ${a:?unset a}
-bash: a: unset a
${變量#關(guān)鍵詞} 若變量內(nèi)容從頭開始的數(shù)據(jù)符合『關(guān)鍵詞』,則將符合的最短數(shù)據(jù)切除
${變量##關(guān)鍵詞} 若變量內(nèi)容從頭開始的數(shù)據(jù)符合『關(guān)鍵詞』,則將符合的最長數(shù)據(jù)切除
${變量%關(guān)鍵詞} 若變量內(nèi)容從尾向前的數(shù)據(jù)符合『關(guān)鍵詞』,則將符合的最短數(shù)據(jù)切除
${變量%%關(guān)鍵詞} 若變量內(nèi)容從尾向前的數(shù)據(jù)符合『關(guān)鍵詞』,則將符合的最長數(shù)據(jù)切除
${變量/舊字符串/新字符串} 若變量內(nèi)容符合『舊字符串』則『第一個(gè)舊字符串會(huì)被新字符串替代』
${變量//舊字符串/新字符串} 若變量內(nèi)容符合『舊字符串』則『全部的舊字符串會(huì)被新字符串替代』
索引及切片
[root@newrain ~]# a=12345678
[root@newrain ~]# echo ${a:5} //從第5位開始截取
678
[root@newrain ~]# echo ${a:3:4}
4567
[root@newrain ~]# echo ${a:2:-1}
34567
[root@newrain ~]# echo ${a:2:-2}
3456
[root@newrain ~]# url=www.sina.com.cn
[root@newrain ~]# echo ${#url} //獲取變量的長度
15
[root@newrain ~]# echo ${url} //正常顯示變量
www.sina.com.cn
變量內(nèi)容的刪除
[root@newrain ~]# echo ${url#*.} 從前往后,最短匹配
sina.com.cn
[root@newrain ~]# echo ${url##*.} 從前往后,最長匹配
cn
[root@newrain ~]# echo ${url%.*} 從后往前,最短匹配
www.sina.com
[root@newrain ~]# echo ${url%%.*} 從后往前,最長匹配
www
[root@newrain ~]# echo ${url#a.}
www.sina.com.cn
[root@newrain ~]# echo ${url#*a.}
com.cn
變量內(nèi)容的替換
$ a=123456123789
$ echo ${a/1/} 第一次匹配的被替換
23456123789
$ echo ${a//1/} 全局的匹配被替換
2345623789
$ echo ${a/1/x}
x23456123789
$ echo ${a//1/x}
x23456x23789
例: file=/dir1/dir2/dir3/my.file.txt
${file#*/}: 拿掉第一條 / 及其左邊的字符串:dir1/dir2/dir3/my.file.txt ${file##*/}: 拿掉最后一條 / 及其左邊的字符串:my.file.txt
${file#*.}: 拿掉第一個(gè) . 及其左邊的字符串:file.txt
${file##*.}: 拿掉最后一個(gè) . 及其左邊的字符串:txt
${file%/*}: 拿掉最后條 / 及其右邊的字符串:/dir1/dir2/dir3 ${file%%/*}: 拿掉第一條 / 及其右邊的字符串:(空值)
${file%.*}: 拿掉最后一個(gè) . 及其右邊的字符串:/dir1/dir2/dir3/my.file ${file%%.*}: 拿掉第一個(gè) . 及其右邊的字符串:/dir1/dir2/dir3/my
記憶的方法為:
# 是去掉左邊(在鍵盤上 # 在 $ 之左邊)
% 是去掉右邊(在鍵盤上 % 在 $ 之右邊)
單一符號(hào)是最小匹配;兩個(gè)符號(hào)是最大匹配(貪婪匹配)。
$ a=123
$ echo ${#a} 表示$var的長度
3
basename 命令
basename 是去除目錄后剩下的名字
# 不會(huì)檢測(cè)文件系統(tǒng),只是取路徑的最后一段,將他截取出來
例:
#temp=/home/temp/1.test
#base=`basename $temp`
#echo $base
結(jié)果為:1.test
dirname 是去除文件的目錄名
# 不會(huì)檢測(cè)文件系統(tǒng),默認(rèn)路徑的最后一段為文件名,把它扇區(qū)
例:
#temp=/home/temp/1.test
#dir=`dirname $temp`
#echo $dir
結(jié)果為:/home/temp
dirname 獲取當(dāng)前腳本的路徑
$( cd $( dirname $0 ) ; pwd )
測(cè)試
test 條件
條件為真返回 0,條件為假返回 1
[ 條件 ]
test 能夠理解3種類型的表達(dá)式
1.文件測(cè)試
2.字符串比較
3.數(shù)字比較
字符串
-n STRING
# -n 字符串長度不為零
-z STRING
# -z 字符串長度為0
STRING1 = STRING2
# = 判斷兩個(gè)字符串是否一樣
STRING1 != STRING2
# != 判斷兩個(gè)字符串是否不一樣
數(shù)字
eq 等于 ne 不等于 #
ge 大于等于 le 小于等于 #
gt 大于 lt 小于 #
文件
test
-f 存在且是普通文件 # 重要
-d 存在且是目錄 #
-h 存在且是符號(hào)鏈接
-b 塊設(shè)備
-c 字符設(shè)備
-e 文件存在 #
流控制:
?在一個(gè)shell腳本中的命令執(zhí)行順序稱作腳本的流。大多數(shù)腳本會(huì)根據(jù)一個(gè)或多個(gè)條件來改變它們的流。
?流控制命令:能讓腳本的流根據(jù)條件而改變的命令稱為條件流控制命令
?exit語句:退出程序的執(zhí)行,并返回一個(gè)返回碼,返回碼為0正常退出,非0為非正常退出,例如:
?exit 0
條件判斷
If代碼返回0表示真,非0為假
if語句語法如下: 1
if [ $1 -eq 1 ]
then
echo '等于1'
elif [ $1 -eq 2 ]
then
echo '等于二'
else
echo '既不等一,也不等于二'
fi
例:
#!/bin/bash
read -p "請(qǐng)輸入號(hào)碼: " num
if [ $num = 1 ];then
echo "1"
elif [ $num = 2 ];then
echo "2"
else
echo "輸入有誤!"
fi
例:腳本if.sh,必須在腳本后加上適當(dāng)?shù)膮?shù)腳本才能正確執(zhí)行
#!/bin/bash
if [ "$1" = "hello" ]; then
echo "Hello! How are you ?"
elif [ "$1" = "" ]; then
echo "You MUST input parameters"
else
echo "The only accept parameter is hello"
fi
練習(xí)(選做):
1)檢測(cè)apache是否運(yùn)行,如果沒有運(yùn)行則啟動(dòng),并記錄啟動(dòng)的時(shí)間,保存到日志中。
2)測(cè)試ip地址主機(jī)位從2到100的機(jī)器是否存活,并把存活的機(jī)器記錄到文本文件alivehost.txt內(nèi)。(使用ping命令)
多個(gè)條件聯(lián)合
邏輯與
if [ $condition1 ] && [ $condition2 ]
if [ $condition -a $condition2 ]
if [[ $condition1 && $condition2 ]]
邏輯或
if [ $condition1 ] || [ $condition2 ]
if [ $condition -o $condition2 ]
if [[ $condition1 || $condition2 ]]
# test 和 [] 中 我們可以使用 [ $condition1 ] && [ $condition2 ] 或者 [ $condition -a $condition2 ]
# 在 [[]] 這種情況,我們可以直接使用[[ $condition1 && $condition2 ]]
建議在if中直接使用[[]]這種方式,這種方式更加穩(wěn)定。[[]] shell的一個(gè)命令。
-a && 邏輯與 and 兩端的條件都可以成立
-o || 邏輯或 or 兩端的條件有一段成立就行
練習(xí):
編寫腳本port.sh,執(zhí)行腳本后顯示系統(tǒng)的httpd、ftp、ssh、sendmail這些服務(wù)是否開啟
case
case 語句是 shell 中流控制的第二種方式,語法如下:
case $word in
pattern1)
list1
;;
pattern2)
list2
;;
patternN)
listN
;;
*)
list*
;;
esac
命令;;表明流應(yīng)該跳轉(zhuǎn)到case語句的最后,類似C語言中的break指令。
練習(xí):建立腳本case.sh,當(dāng)執(zhí)行時(shí),要求我們?cè)阪I盤輸入適當(dāng)?shù)闹?one|two|three),當(dāng)輸入正確時(shí)并打印,當(dāng)輸入錯(cuò)誤 時(shí)會(huì)提示你,應(yīng)該輸入正確的值。
作業(yè)
1. ping主機(jī)測(cè)試
2. 判斷一個(gè)用戶是否存在
3. 判斷當(dāng)前內(nèi)核主版本是否為3,且次版本是否大于10
4. 判斷vsftpd軟件包是否安裝,如果沒有則自動(dòng)安裝 (yum是否能用,不能用自動(dòng)修復(fù),安裝完成測(cè)試以下,是否能用。)
5. 判斷httpd是否運(yùn)行
6. 判斷指定的主機(jī)是否能ping通,必須使用$1變量
7. 報(bào)警腳本,要求如下:
根分區(qū)剩余空間小于20%
內(nèi)存已用空間大于80%
向用戶alice發(fā)送告警郵件
配合crond每5分鐘檢查一次
echo "郵件正文" | mail -s "郵件主題" alice 可以報(bào)警
8. 判斷用戶輸入的是否是數(shù)字
read -p "請(qǐng)輸入:" get
case $get in
[0-9][0-9]*) #判斷輸入是否是數(shù)字
echo -e "你輸入是數(shù)字。\n"
;;
*)
echo -e "你輸入的不是數(shù)字。\n"
;;
esac
case $var in
模式1)
執(zhí)行1
;;
模式2)
執(zhí)行2
;;
模式3)
執(zhí)行3
;;
*)
執(zhí)行4
esac
第一行: 聲明case關(guān)鍵字調(diào)用case語法, 緊跟的“變量”一般為用戶的輸入值, in代表從下方的各個(gè)模式進(jìn)行匹配
第2-4行: 匹配到“模式1”后進(jìn)行命令的輸出或執(zhí)行, 模式1: 一般為字符或數(shù)值
第11-12行: 當(dāng)用戶輸入的字符不存在匹配模式時(shí), 直接執(zhí)行或打印*)下的命令或語句
示例: