Shell詳解---一篇搞定
1.1 前言
1.1.1 為什麼學Shell
Shell指令碼語言是實現Linux/UNIX系統管理及自動化運維所必備的重要工具, Linux/UNIX系統的底層及基礎應用軟體的核心大都涉及Shell指令碼的內容。每一個合格 的Linux系統管理員或運維工程師,都需要能夠熟練地編寫Shell指令碼語言,並能夠閱 讀系統及各類軟體附帶的Shell指令碼內容。只有這樣才能提升運維人員的工作效率,適 應曰益複雜的工作環境,減少不必要的重複工作,從而為個人的職場發展奠定較好的基礎
1.1.2 什麼是shell
Shell是一個命令直譯器,它在作業系統的最外層,負責直接與使用者對話,把使用者的輸入解釋給作業系統,並處理各種各樣的作業系統的輸出結果,輸出螢幕返回給使用者。
這種對話方式可以是:
互動的方式:從鍵盤輸入命令,通過/bin/bash的解析,可以立即得到Shell的迴應
[[email protected] ~]# ls anaconda-ks.cfg [[email protected] ~]# echo ls |bash anaconda-ks.cfg
非互動的方式: 指令碼
1.1.3 什麼是Shell指令碼
命令、變數和流程控制語句等有機的結合起來
shell指令碼擅長處理純文字型別的資料,而linux中,幾乎所有的配置檔案,日誌,都是純文字型別檔案
1.1.4 指令碼語言的種類
一、編譯型語言
定義:指用專用的編譯器,針對特定的操作平臺(作業系統)將某種高階語言原始碼一次性翻譯成可被硬體平臺直接執行的二進位制機器碼(具有運算元,指令、及相應的格式),這個過程叫做編譯(./configure make makeinstall );編譯好的可執行性檔案(.exe),可在相對應的平臺上執行(移植性差,但執行效率高)。。
典型的編譯型語言有, C語言、C++等。
另外,Java語言是一門很特殊的語言,Java程式需要進行編譯步驟,但並不會生成特定平臺的二進位制機器碼,它編譯後生成的是一種與平臺無關的位元組碼檔案(*.class)(移植性好的原因),這種位元組碼自然不能被平臺直接執行,執行時需要由直譯器解釋成相應平臺的二進位制機器碼檔案;大多數人認為Java是一種編譯型語言,但我們說Java即是編譯型語言,也是解釋型語言也並沒有錯。
二、解釋型語言
定義:指用專門直譯器對源程式逐行解釋成特定平臺的機器碼並立即執行的語言;相當於把編譯型語言的編譯連結過程混到一起同時完成的。
解釋型語言執行效率較低,且不能脫離直譯器執行,但它的跨平臺型比較容易,只需提供特定直譯器即可。
常見的解釋型語言有, Python(同時是指令碼語言)與Ruby等。
三、指令碼語言
定義:為了縮短傳統的編寫-編譯-連結-執行(edit-compile-link-run)過程而建立的計算機程式語言。
特點:程式程式碼即是最終的執行檔案,只是這個過程需要直譯器的參與,所以說指令碼語言與解釋型語言有很大的聯絡。指令碼語言通常是被解釋執行的,而且程式是文字檔案。
典型的指令碼語言有,JavaScript,Python,shell等。
其他常用的指令碼語句種類
PHP是網頁程式,也是指令碼語言。是一款更專注於web頁面開發(前端展示)的指令碼語言,例如:Dedecms,discuz。PHP程式也可以處理系統日誌,配置檔案等,php也可以呼叫系統命令。
Perl指令碼語言。比shell指令碼強大很多,語法靈活、複雜,實現方式很多,不易讀,團隊協作困難,但仍不失為很好的指令碼語言,存世大量的程式軟體。MHA高可用Perl寫的
Python,不但可以做指令碼程式開發,也可以實現web程式以及軟體的開發。近兩年越來越多的公司都會要求會Python。
Shell指令碼與php/perl/python語言的區別和優勢?
shell指令碼的優勢在於處理作業系統底層的業務 (linux系統內部的應用都是shell指令碼完成)因為有大量的linux系統命令為它做支撐。2000多個命令都是shell指令碼程式設計的有力支撐,特別是grep、awk、sed等。例如:一鍵軟體安裝、優化、監控報警指令碼,常規的業務應用,shell開發更簡單快速,符合運維的簡單、易用、高效原則.
PHP、Python優勢在於開發運維工具以及web介面的管理工具,web業務的開發等。處理一鍵軟體安裝、優化,報警指令碼。常規業務的應用等php/python也是能夠做到的。但是開發效率和複雜比用shell就差很多了。
系統環境說明
[[email protected] scripts]# cat /etc/redhat-release CentOS Linux release 7.4.1708 (Core) [[email protected] scripts]# uname -r 3.10.0-693.el7.x86_64 [[email protected] scripts]# getenforce Disabled [[email protected] scripts]# systemctl status firewalld.service ● firewalld.service - firewalld - dynamic firewall daemon Loaded: loaded (/usr/lib/systemd/system/firewalld.service; disabled; vendor preset: enabled) Active: inactive (dead) Docs: man:firewalld(1)
1.1.5 系統中的shell
檢視系統中的命直譯器
[[email protected] ~]# cat /etc/shells /bin/sh /bin/bash /sbin/nologin /usr/bin/sh /usr/bin/bash /usr/sbin/nologin
常用作業系統的預設shell
1.Linux是Bourne Again shell(bash)
2.Solaris和FreeBSD預設的是Bourne shell(sh)
3.AIX下是Korn Shell(ksh)
4.HP-UX預設的是POSIX shell(sh)
[[email protected] ~]# echo $SHELL /bin/bash
bash版本
[[email protected] scripts]# bash -version
GNU bash, 版本 4.2.46(2)-release (x86_64-redhat-linux-gnu) Copyright (C) 2011 Free Software Foundation, Inc. 許可證 GPLv3+: GNU GPL 許可證版本3或者更高 <http://gnu.org/licenses/gpl.html>
這是自由軟體,您可以自由地更改和重新發布。 在法律允許的範圍內沒有擔保.
bash 破殼漏洞
使用 命令 env x='() { :;}; echo be careful' bash -c "echo this is a test" 如果返回結果為一行,則為正常, [[email protected] ~]# env x='() { :;}; echo be careful' bash -c "echo this is a test" this is a test #解決辦法 升級當前的bash版本 yum install update bash
sh與bash 的關係
[[email protected] ~]# ll /bin/sh lrwxrwxrwx. 1 root root 4 11月 13 11:15 /bin/sh -> bash
/bin與 /user/bin 的關係
[[email protected] ~]# ll /bin -d lrwxrwxrwx. 1 root root 7 11月 13 11:15 /bin -> usr/bin
1.2 指令碼書寫規範
1.2.1 指令碼統一存放目錄
[[email protected] ~]# mkdir -p /server/scripts/ [[email protected] ~]# cd /server/scripts/
1.2.2 選擇直譯器
注意格式 ↓
其中開頭的"#!"字元又稱為幻數,在執行bash指令碼的時候,核心會根據"#!"後的直譯器來確定該用那個程式解釋這個指令碼中的內容。
[[email protected] scripts]# head -1 /etc/init.d/* ==> /etc/init.d/functions <== # -*-Shell-script-*- ==> /etc/init.d/netconsole <== #!/bin/bash ==> /etc/init.d/network <== #! /bin/bash
1.2.3 編輯指令碼使用vim
使用 .vimrc 檔案,能夠快速的生成開頭的註釋資訊
[[email protected] scripts]# cat ~/.vimrc autocmd BufNewFile *.py,*.cc,*.sh,*.java exec ":call SetTitle()" func SetTitle() if expand("%:e") == 'sh' call setline(1,"#!/bin/bash") call setline(2, "##############################################################") call setline(3, "# File Name: ".expand("%")) call setline(4, "# Version: V1.0") call setline(5, "# Author: clsn") call setline(6, "# Organization: http://blog.znix.top") call setline(7, "# Created Time : ".strftime("%F %T")) call setline(8, "# Description:") call setline(9, "##############################################################") call setline(10, "") endif endfunc
使用後的效果
[[email protected] scripts]# cat scripts_test.sh #!/bin/bash ############################################################## # File Name: scripts_test.sh # Version: V1.0 # Author: clsn # Organization: http://blog.znix.top # Created Time : 2017-12-04 11:39:57 # Description: First scripts file ##############################################################
在Shell指令碼中,跟在#後面的內容表示註釋。註釋部分不會被執行,僅給人看。註釋可以自成一行,也可以跟在命令後面,與命令同行。要養成寫註釋的習慣,方便自己與他人。
最好不用中文註釋,因為在不同字符集的系統會出現亂碼。(字符集為zh_CN.UTF-8,為中文)。
1.2.4 檔名規範
名字要有意義,並且結尾以 .sh 結束
1.2.5 開發的規範和習慣小結
1) 放在統一的目錄
2) 指令碼以.sh為副檔名
3) 開頭指定指令碼直譯器。
4) 開頭加版本版權等資訊,可配置~/.vimrc檔案自動新增。
5) 指令碼不要用中文註釋,儘量用英文註釋。
6) 程式碼書寫優秀習慣
a、成對的內容一次性寫出來,防止遺漏,如[ ]、' '、" "等
b、[ ]兩端要有空格,先輸入[ ],退格,輸入2個空格,再退格寫。
c、流程控制語句一次書寫完,再新增內容。(if 條件 ; then 內容;fi)ddd
d、通過縮排讓程式碼易讀。
f、指令碼中的引號都是英文狀態下的引號,其他字元也是英文狀態。
1.3 shell指令碼的執行
1.3.1 執行指令碼的辦法
sh/bash scripts.sh chown +x ./scripts.sh && ./scripts.sh source scripts.sh . (空格) scripts.sh cat oldboyedu.sh |bash # 效率較低
source 與 . (點) 的作用
soucre命令
[[email protected] ~]# help source |head -2 source: source 檔名 [引數] 在當前 shell 中執行一個檔案中的命令。
. (點)
[[email protected] scripts]# help . |head -2 .: . 檔名 [引數] 在當前 shell 中執行一個檔案中的命令。
1.3.2 sh 於 source的區別
[[email protected] scripts]# sh clsn_test.sh Hello World! [[email protected] scripts]# echo $clsn # sh 新建一個Shell視窗(新建一個程序)執行一個檔案中的命令。 [[email protected] scripts]# source clsn_test.sh Hello World! [[email protected] scripts]# echo $clsn Hello World!
面試題:
問sh test.sh後echo $user返回的結果__空_ ?
[[email protected] scripts]# cat test.sh #!/bin/bash user=`whoami`
1.4 Shell的變數
1.4.1 什麼是變數
變數可以分為兩類:環境變數(全域性變數)和普通變數(區域性變數)
環境變數也可稱為全域性變數,可以在建立他們的Shell及其派生出來的任意子程序shell中使用,環境變數又可分為自定義環境變數和Bash內建的環境變數
普通變數也可稱為區域性變數,只能在建立他們的Shell函式或Shell指令碼中使用。普通變數一般是由開發者使用者開發指令碼程式時建立的。
特殊變數
1.4.2 環境變數
使用 env/declare/set/export -p 命令檢視系統中的環境變數,這三個命令的的輸出方式稍有不同。
[[email protected] scripts]# env XDG_SESSION_ID=1 HOSTNAME=clsn TERM=linux SHELL=/bin/bash HISTSIZE=1000 SSH_CLIENT=10.0.0.1 5537 22 SSH_TTY=/dev/pts/0 USER=root ~~~
輸出一個系統中的 環境變數
[[email protected] ~]# echo $LANG zh_CN.UTF-8
1.4.3 普通變數
本地變數在使用者當前的Shell生存期的指令碼中使用。例如,本地變數OLDBOY取值為bingbing,這個值在使用者當前Shell生存期中有意義。如果在Shell中啟動另一個程序或退出,本地變數值將無效
定義普通變數實踐
[[email protected] ~]# a=1 [[email protected] ~]# b='2' [[email protected] ~]# c="3" [[email protected] ~]# echo "$a" 1 [[email protected] ~]# echo "$b" 2 [[email protected] ~]# echo "${c}"
提示:$變數名錶示輸出變數,可以用$c和${c}兩種用法
小結:連續普通字串內容賦值給變數,不管用什麼引號或者不用引號,它的內容是什麼,列印變數就輸出什麼
1.4.4 export命令
[[email protected] ~]# help export export: export [-fn] [名稱[=值] ...] 或 export -p 為 shell 變數設定匯出屬性。 標記每個 NAME 名稱為自動匯出到後續命令執行的環境。如果提供了 VALUE 則匯出前將 VALUE 作為賦值。
export命令的說明
當前shell視窗及子shell視窗生效
在新開的shell視窗不會生效,生效需要寫入配置檔案
# 定義變數
[[email protected] scripts]# CSLN=clsn [[email protected] scripts]# export CSLN1=1
# 當前視窗檢視
[[email protected] scripts]# echo $CSLN clsn [[email protected] scripts]# echo $CSLN1 1
# 編寫測試指令碼
[[email protected] scripts]# vim quanju.sh #!/bin/bash echo $CSLN echo $CSLN1
# 使用sh執行
[[email protected] scripts]# sh quanju.sh 1
# 使用source 執行
[[email protected] scripts]# source quanju.sh clsn 1
1.4.5 環境變數相關配置檔案
/etc/proflie
/etc/bashrc
~/.bashrc
~/.bash_profile
/etc/proflie.d/ # 目錄
四檔案讀取順序(CentOS6和7都一樣)
① /etc/profile
② ~/.bash_profile
③ ~/.bashrc
④ /etc/bashrc
檔案讀取過程示意圖
驗證四檔案讀取順序的方法
sed -i '1a echo "$(date +%T-%s) /etc/profile1" >>/tmp/clsn' /etc/profile sed -i '$a echo "$(date +%T-%s) /etc/profile2" >>/tmp/clsn' /etc/profile sed -i '1a echo "$(date +%T-%s) /etc/bashrc1" >>/tmp/clsn' /etc/bashrc sed -i '$a echo "$(date +%T-%s) /etc/bashrc2" >>/tmp/clsn' /etc/bashrc sed -i '1a echo "$(date +%T-%s) ~/.bashrc1" >>/tmp/clsn' ~/.bashrc sed -i '$a echo "$(date +%T-%s) ~/.bashrc2" >>/tmp/clsn' ~/.bashrc sed -i '1a echo "$(date +%T-%s) ~/.bash_profile1" >>/tmp/clsn' ~/.bash_profile sed -i '$a echo "$(date +%T-%s) ~/.bash_profile2" >>/tmp/clsn' ~/.bash_profile
1.4.6 環境變數的知識小結
ü 變數名通常要大寫。
ü 變數可以在自身的Shell及子Shell中使用。
ü 常用export來定義環境變數。
ü 執行env預設可以顯示所有的環境變數名稱及對應的值。
ü 輸出時用“$變數名”,取消時用“unset變數名”。
ü 書寫crond定時任務時要注意,指令碼要用到的環境變數最好先在所執行的Shell指令碼中重新定義。
ü 如果希望環境變數永久生效,則可以將其放在使用者環境變數檔案或全域性環境變數檔案裡。
1.4.7 變數中引號的使用
只有在變數的值中有空格的時候,會使用引號。
單引號與雙引號的區別在於,是否能夠解析特殊符號。
[[email protected] ~]# name=znix [[email protected] ~]# name2='clsn' [[email protected] ~]# name3="http://blog.znix.top" [[email protected] ~]# echo $name znix [[email protected] ~]# echo $name2 clsn [[email protected] ~]# echo $name3 http://blog.znix.top [[email protected] ~]# name4='cl sn' [[email protected] ~]# echo $name4 cl sn [[email protected] ~]# name5="cl sn" [[email protected] ~]# echo $name5 cl sn [[email protected] ~]# name6='cl sn $PWD' [[email protected] ~]# echo $name6 cl sn $PWD [[email protected] ~]# name6="cl sn $PWD" [[email protected] ~]# echo $name6 cl sn /root
1.4.8 普通變數的要求
1) 內容是純數字、簡單的連續字元(內容中不帶任何空格)時,定義時可以不加任何引號,例如:
a.ClsnAge=22
b.NETWORKING=yes
2) 沒有特殊情況時,字串一律用雙引號定義賦值,特別是多個字串中間有空格時,例如:
a.NFSD_MODULE="no load"
b.MyName="Oldboy is a handsome boy."
3) 當變數裡的內容需要原樣輸出時,要用單引號(M),這樣的需求極少,例如:
a.OLDBOY_NAME='OLDBOY'
變數使用反引號賦值
[[email protected] scripts]# time=`date` [[email protected] scripts]# echo $time 2017年 12月 05日 星期二 09:02:06 CST [[email protected] scripts]# file=`ls` [[email protected] scripts]# echo $file clsn_test.sh panduan.sh quanju.sh yhk.sh
使用${}
列印變數的時候防止出現“金庸新著”的問題
[[email protected] scripts]# time=`date` [[email protected] scripts]# echo $time_day [[email protected] scripts]# echo ${time}_day 2017年 12月 05日 星期二 09:02:06 CST_day [[email protected] scripts]# echo $time-day 2017年 12月 05日 星期二 09:02:06 CST-day
編寫指令碼測試${}
# 使用指令碼測試 [[email protected] scripts]# vim bianliang.sh #!/bin/bash ############################################################# # File Name: bianliang.sh # Version: V1.0 # Author: clsn # Organization: http://blog.znix.top # Created Time : 2017-12-05 09:10:29 # Description: ############################################################# time=`date` echo $timeday echo ${time}day [[email protected] scripts]# sh bianliang.sh 2017年 12月 05日 星期二 09:11:19 CSTday
1.4.9 定義變數名技巧
1. 變數名只能為字母、數字或下劃線,只能以字母或下劃線開頭。
2. 變數名的定義要有一定的規範,並且要見名知意。
示例:
ClsnAge=22 #<==每個單詞的首字母大寫的寫法
clsn_age=22 #<==單詞之間用"_"的寫法
clsnAgeSex=man #<==駝峰語法:首個單詞的首字母小寫,其餘單詞首字母大寫
CLSNAGE=22 #<==單詞全大寫的寫法
3. 一般的變數定義、賦值常用雙引號;簡單連續的字串可以不加引號;希望原樣輸出時使用單引號。
4. 希望變數的內容是命令的解析結果時,要用反引號'',或者用$()把命令括起來再賦值。
1.5 特殊變數
1.5.1 位置變數
常用的特殊位置引數說明
位置變數 |
作用說明 |
$0 |
獲取當前執行的shell指令碼的檔名,如果執行指令碼帶路徑那麼就包括指令碼路徑。 |
$n |
獲取當前執行的shell指令碼的第n個引數值,n=1..9,當n為0時表示指令碼的檔名,如果n大於9用大括號括起來{10},引數以空格隔開。 |
$# |
獲取當前執行的shell指令碼後面接的引數的總個數 |
$* |
獲取當前shell的所有傳參的引數,不加引號同[email protected];如果給$*加上雙引號,例如: “$*”,則表示將所有的引數視為單個字串,相當於“1 2$3”。 |
獲取當前shell的所有傳參的引數,不加引號同$*;如果給[email protected]加上雙引號,例如: “[email protected]”,則表示將所有引數視為不同的獨立字串,相當於“$1” “$2” “$3” “……”,這是將引數傳遞給其他程式的最佳方式,因為他會保留所有內嵌在每個引數裡的任何空白。 |
|
當“$*”和“[email protected]”都加雙引號時,兩者有區別,都不加雙引號時,兩者無區別。 |
0, 1.$2 ~ 引數實踐
[[email protected] scripts]# vim chanshu.sh #!/bin/bash ############################################################# # File Name: chanshu.sh # Version: V1.0 # Author: clsn # Organization: http://blog.znix.top # Created Time : 2017-12-05 09:39:16 # Description: ############################################################# echo $0 echo "第一個引數:" $1 echo "第二個引數:" $2 echo "第11個引數:" ${11} [[email protected] scripts]# sh chanshu.sh chanshu.sh 第一個引數: 第二個引數: 第11個引數: [[email protected] scripts]# sh chanshu.sh 1 2 3 4 5 6 7 8 9 10 11 chanshu.sh 第一個引數: 1 第二個引數: 2 第11個引數: 11
$# 引數實踐
[[email protected] scripts]# vim chanshu.sh ############################################################# # File Name: chanshu.sh # Version: V1.0 # Author: clsn # Organization: http://blog.znix.top # Created Time : 2017-12-05 09:39:16 # Description: ############################################################# echo $0 echo "第一個引數:" $1 echo "第二個引數:" $2 echo "第10個引數:" ${10} echo "第11個引數:" ${11} echo "引數個數:" $# [[email protected] scripts]# sh chanshu.sh 55 2 3 4 5 6 7 8 9 10 11 112 chanshu.sh 第一個引數: 55 第二個引數: 2 第10個引數: 10 第11個引數: 11 引數個數: 12
$* 引數實踐
[[email protected] scripts]# vim chanshu.sh ############################################################# # File Name: chanshu.sh # Version: V1.0 # Author: clsn # Organization: http://blog.znix.top # Created Time : 2017-12-05 09:39:16 # Description: ############################################################# echo $0 echo "第一個引數:" $1 echo "第二個引數:" $2 echo "第10個引數:" ${10} echo "第11個引數:" ${11} echo "引數個數:" $# echo "引數:" $* "chanshu.sh" 18L, 456C 已寫入 [[email protected] scripts]# sh chanshu.sh 55 2 3 4 5 6 7 8 9 10 11 112 chanshu.sh 第一個引數: 55 第二個引數: 2 第10個引數: 10 第11個引數: 11 引數個數: 12 引數: 55 2 3 4 5 6 7 8 9 10 11 112
$* 與 [email protected] 對比實踐
[[email protected] scripts]# set -- "I am" handsome boy.. [[email protected] scripts]# echo $1 I am [[email protected] scripts]# echo $2 handsome [[email protected] scripts]# echo $3 boy.. [[email protected] scripts]# echo $* I am handsome boy.. [[email protected] scripts]# echo [email protected] I am handsome boy.. [[email protected] scripts]# for i in $*;do echo $i ;done I am handsome boy.. [[email protected] scripts]# for i in [email protected];do echo $i ;done I am handsome boy.. [[email protected] scripts]# for i in "[email protected]";do echo $i ;done I am handsome boy.. [[email protected] scripts]# for i in "$*";do echo $i ;done I am handsome boy..
1.5.2 程序狀態變數
Shell程序的特殊狀態變數說明
引數 |
引數說明 |
-n |
不要追加換行 |
-e |
啟用下列反斜槓轉義的解釋 |
-E |
顯式地抑制對於反斜槓轉義的解釋 |
`echo' 對下列反斜槓字元進行轉義: |
|
\n |
換行 |
\r |
回車 |
\t |
橫向製表符 |
\b |
退格 |
\v |
縱向製表符 |
\c |
抑制更多的輸出 |
1.6 定義變數的方式
1.6.1 三種定義變數的方式
1、直接賦值
2、傳參 (傳遞引數)
3、互動式設定變數,使用read命令
1.6.2 read命令說明
在命令列中使用
[[email protected] scripts]# read 132 [[email protected] scripts]# echo $REPLY 132 [[email protected] scripts]# read clsn 456 [[email protected] scripts]# echo $clsn 456 [[email protected] scripts]# echo $REPLY 132
在指令碼中使用
[[email protected] scripts]# vim clsn_test.sh #!/bin/bash read -p '請輸入:' clsn echo $clsn
執行結果
[[email protected] scripts]# sh clsn_test.sh 請輸入:clsn_znix clsn_znix
read命令的幫助說明
[[email protected] scripts]# read --help -bash: read: --: 無效選項 read: 用法:read [-ers] [-a 陣列] [-d 分隔符] [-i 緩衝區文字] [-n 讀取字元數] [-N 讀取字元數] [-p 提示符] [-t 超時] [-u 檔案描述符] [-s不顯示終端的任何輸入] [名稱 ...]
1.6.3 定義方法實踐
直接賦值方法
[[email protected] scripts]# vim bianliang.sh # File Name: bianliang.sh # Version: V1.0 # Author: clsn # Organization: http://blog.znix.top # Created Time : 2017-12-05 09:10:29 # Description: ############################################################## name=CLSN age=22 sex=Man hobby=`ls` ethFile=/etc/sysconfig/network-scripts/ifcfg-eth0 echo $hobby ls $ethFile [[email protected] scripts]# sh bianliang.sh bianliang.sh chanshu.sh clsn.sh clsn_test.sh panduan.sh quanju.sh xiugaizhuji.sh yhk.sh /etc/sysconfig/network-scripts/ifcfg-eth0
傳參 (傳遞引數)
[[email protected] scripts]# vim bianliang.sh ############################################################## # File Name: bianliang.sh # Version: V1.0 # Author: clsn # Organization: http://blog.znix.top # Created Time : 2017-12-05 09:10:29 # Description: ############################################################## name=CLSN age=22 sex=Man hobby=$1 ethFile=$2 echo $hobby ls $ethFile [[email protected] scripts]# sh bianliang.sh clsn /etc/hostname clsn /etc/hostname
互動式設定變數 read
[[email protected] scripts]# vim yhk.sh #!/bin/bash ############################################################## # File Name: yhk.sh # Version: V1.0 # Author: clsn # Organization: http://blog.znix.top # Created Time : 2017-12-04 17:01:44 # Description: ############################################################## read -p "請輸入你的銀行卡號:" Yhk read -s -p "請輸入密碼:" miMa echo echo "你的銀行卡號:" $Yhk echo "你的密碼為:" $miMa # 測試結果 [[email protected] scripts]# sh yhk.sh 請輸入你的銀行卡號:123456 請輸入密碼: 你的銀行卡號: 123456 你的密碼為: 123456
1.6.4 寫一個互動指令碼,實現能夠定義主機名及IP地址
指令碼內容↓
[[email protected] scripts]# cat xiugaizhuji.sh #!/bin/bash ############################################################# # File Name: jiaohu.sh # Version: V1.0 # Author: clsn # Organization: http://blog.znix.top # Created Time : 2017-12-05 10:55:42 # Description: ############################################################# ethFile=/etc/sysconfig/network-scripts/ifcfg-eth[01] Now_eth=`hostname -I|awk -F "[. ]+" '{print $4}'` read -p "請輸入主機名:" Hostname read -p "請輸入IP地址的主機位:" HostIP hostnamectl set-hostname $Hostname sed -i "s#${Now_eth}#${HostIP}#g" $ethFile read -p "是否重啟伺服器:{yes/no}" REboot if [ $REboot == yes ] then echo "系統將在10秒後重啟!" shutdown -r 10 else echo "請稍後手動重啟系統!" fi
指令碼測試結果
[[email protected] scripts]# sh xiugaizhuji.sh 請輸入主機名:clsn 請輸入IP地址的主機位:180 是否重啟伺服器:{yes/no}yes 系統將在10秒後重啟! [[email protected] scripts]# sh xiugaizhuji.sh 請輸入主機名:clsn 請輸入IP地址的主機位:180 是否重啟伺服器:{yes/no}no 請稍後手動重啟!
1.7 變數的子串
1.7.1 變數子串說明
表示式 |
說明 |
${parameter} |
返回變數$parameter的內容 |
${#parameter} |
返回變內容的長度(按字元),也適用於特殊變數 |
${parameterioffset} |
在變數${parameter}中,從位置offset之後開始提取子串到結尾 |
${parameter:offset:length} |
在變數${parameter}中,從位置offset之後開始提取長度為length的子串 |
${parameter#word} |
從變數${parameter}開頭開始刪除最短匹配的word子串 |
${parameter##word} |
從變數${parameter}開頭開始刪除最長匹配的word子串 |
${parameter%word} |
從變數${parameter}結尾開始刪除最短匹配的word子串 |
${parameter%%word} |
從變數${parameter}結尾開始刪除最長匹配的word子串 |
${parameter/pattem/string} |
使用string代替第一個匹配的pattern |
${parameter//pattem/string} |
使用string代替所有匹配的pattern |
計算變賦值的長度
[[email protected] scripts]# clsn=http://blog.znix.top [[email protected] scripts]# echo ${clsn} |wc -L 20 [[email protected] scripts]# echo ${#clsn} 20 [[email protected] scripts]# time echo ${clsn} |wc -L 20 real 0m0.002s user 0m0.002s sys 0m0.000s [[email protected] scripts]# time echo ${#clsn} 20 real 0m0.000s user 0m0.000s sys 0m0.000s
擷取變數中的字元
[[email protected] scripts]# clsn=abcABC123ABCabc [[email protected] scripts]# echo ${clsn#abc} ABC123ABCabc [[email protected] scripts]# echo ${clsn##abc} ABC123ABCabc [[email protected] scripts]# echo ${clsn%abc} abcABC123ABC [[email protected] scripts]# echo ${clsn%%abc} abcABC123ABC [[email protected] scripts]# echo ${clsn#a*c} ABC123ABCabc [[email protected] scripts]# echo ${clsn##a*c} [[email protected] scripts]# echo ${clsn%a*c} abcABC123ABC [[email protected] scripts]# echo ${clsn%%a*c} [[email protected] scripts]# echo ${clsn#a*C} 123ABCabc [[email protected] scripts]# echo ${clsn#a*C} 123ABCabc [[email protected] scripts]# echo ${clsn##a*C} abc [[email protected] scripts]# echo ${clsn%a*c} abcABC123ABC [[email protected] scripts]# echo ${clsn%A*c} abcABC123 [[email protected] scripts]# echo ${clsn%%A*c} abc
替換變數內容
[[email protected] scripts]# echo $clsn abcABC123ABCabc [[email protected] scripts]# echo ${clsn/abc/clsn} clsnABC123ABCabc [[email protected] scripts]# echo ${clsn//abc/clsn} clsnABC123ABCclsn
有關上述匹配刪除的小結
#表示從幵頭刪除匹配最短。
##表示從開頭刪除匹配最長。
%表示從結尾刪除匹配最短。
%%表示從結尾刪除匹配最長。
a*c表示匹配的突符串,*表示匹配所有,a*c匹配開頭為a、中間為任意多個字元、結尾為c的字串。
a*C表示匹配的字串,*表示匹配所有,a*C匹配開頭為a、中間為任意多個字元、結尾為C的字串。
有關替換的小結
一個“/”表示替換匹配的第-個字串。
兩個“/”表示替換匹配的所有字串。
1.7.2 Shell的特殊擴充套件變數說明
表示式 |
說明 |
${parameter:-word} |
如果parameter的變數值為空或未賦值,則會返回word字串並替代變數的值用途.如果變數未定義,則返回備用的值,防止變數為空值或因未定義而導致異常 |
${parameter:=word} |
如果parameter的變數值為空或未賦值,則設定這個變數值為word,並返回其值。位置變數和特殊變數不適用用途:基本同上一個${parameter>word},但該變數又額外給parameter變數賦值了 |
${parameter:?word} |
如果parameter變數值為空或未賦值,那麼word字串將被作為標準錯誤輸出,否則輸出變數的值。用途:用於捕捉由於變數未定義而導致的錯誤,並退出程式 |
${parameter:+word} |
如果parameter變數值為空或未賦值,則什麼都不做,否則word字串將替代變數的值 |
特殊變數實踐
指令碼內容
[[email protected] scripts]# cat clsn.sh #!/bin/bash ############################################################# # File Name: clsn.sh # Version: V1.0 # Author: clsn # Organization: http://blog.znix.top # Created Time : 2017-12-05 12:13:38 # Description: ############################################################# dir= echo ${dir:-/tmp} echo ${dir} echo ${dir:=/mnt} echo ${dir} dir2= (空格) echo ${dir2-/tmp} echo ${dir2} echo ${dir2:-/tmp} echo ${dir2} echo ${dir2=/mnt} echo ${dir2}
測試結果
[[email protected] scripts]# sh clsn.sh /tmp /mnt /mnt /tmp
至此shell中的變數就都介紹完了
1.8 變數的數值計算
1.8.1 僅支援整數的運算
echo $((數學運算表示式))
# 形式一 [[email protected] scripts]# echo $((1 + 1)) 2 [[email protected] scripts]# echo $((2*7-3/6+5)) 19 # 形式二 [[email protected] scripts]# ((clsn=2*8)) [[email protected] scripts]# echo $clsn 16 # 形式三 [[email protected] scripts]# znix=$((2*7-3/6+5)) [[email protected] scripts]# echo $znix 19
延伸產物(重要)
i++ 自增1
i-- 自減1
++i
--i
示例:
[[email protected] scripts]# i=1 [[email protected] scripts]# echo $((i++)) 1 [[email protected] scripts]# echo $((i++)) 2 [[email protected] scripts]# echo $((i--)) 3 [[email protected] scripts]# echo $((i--)) 2 [[email protected] scripts]# echo $((i--)) 1 [[email protected] scripts]# echo $((++i)) 1 [[email protected] scripts]# echo $((++i)) 2 [[email protected] scripts]# echo $((++i)) 3 [[email protected] scripts]# echo $((--i)) 2 [[email protected] scripts]# echo $((--i)) 1 [[email protected] scripts]# echo $((--i)) 0
記憶方法:++,--
變數a在前,表示式的值為a,然後a自增或自減,變數a在符號後,表示式值自增或自減,然後a值自增或自減。
let命令
[[email protected] scripts]# i=1 [[email protected] scripts]# i=i+1 [[email protected] scripts]# echo $i i+1 [[email protected] scripts]# i=1 [[email protected] scripts]# let i=i+1 [[email protected] scripts]# echo $i 2
expr 命令
1.整數計算
2.判斷副檔名
3.判斷輸入是否為整數,非整數返回值為2
4.計算變數的長度
[[email protected] scripts]# expr 1+1 1+1 [[email protected] scripts]# expr 1 + 1 2 [[email protected] scripts]# expr 1 * 1 expr: 語法錯誤 [[email protected] scripts]# expr 1 \* 1 1
非整數返回值為2 示例:
[[email protected] scripts]# expr 1 + 1 2 [[email protected] scripts]# echo $? 0 [[email protected] scripts]# expr -1 + 1 0 [[email protected] scripts]# echo $? 1 [[email protected] scripts]# expr a + 1 expr: 非整數引數 [[email protected] scripts]# echo $? 2
$[]運算子
[[email protected] scripts]# echo $[1+2] 3 [[email protected] scripts]# echo $[1-2] -1 [[email protected] scripts]# echo $[1*2] 2 [[email protected] scripts]# echo $[1/2] 0
[[email protected] scripts]# typeset -i A=2017 B=2018 [[email protected] scripts]# A=A+B [[email protected] scripts]# echo $A 4035
1.8.2 可以進行小數運算的命令
bc 命令
# 安裝 bc 依賴於base源 [[email protected] scripts]# yum -y install bc
互動模式測試bc命令
[[email protected] scripts]# bc bc 1.06.95 Copyright 1991-1994, 1997, 1998, 2000, 2004, 2006 Free Software Foundation, Inc. 1+1 2 [[email protected] scripts]# echo 1+1.1|bc 2.1
免互動模式測試bc命令
[[email protected] scripts]# echo 'scale=6;1/3'|bc .333333
python 命令
[[email protected] scripts]# file `which yum ` /usr/bin/yum: Python script, ASCII text executable [[email protected] scripts]# python >>> import os >>> os.system('df -h') >>> 1+1.1 2.1 >>>exit()
awk 命令
[[email protected] ~]# echo "7.7 3.8"|awk '{print ($1-$2)}' 3.9 [[email protected] ~]# echo "358 113"|awk '{print ($1-3)/$2}' 3.14159 [[email protected] ~]# echo "3 9"|awk '{print ($1+3)*$2}' 54 [[email protected] scripts]# awk BEGIN'{print 1.2+3.3}' 4.5
1.8.3 運算相關練習題
1.8.3.1 【練習題】實現一個加減乘除等功能的計算器
實現指令碼:
[[email protected] scripts]# cat jishuanqi.sh #!/bin/bash ############################################################# # File Name: jishuanqi.sh # Version: V1.0 # Author: clsn # Organization: http://blog.znix.top # Created Time : 2017-12-06 08:57:13 # Description: ############################################################# read -p "請輸入第一個整數:" a read -p "請輸入第二個整數:" b echo $a + $b =$(($a+$b)) echo $a - $b =$(($a-$b)) echo $a \* $b =$(($a*$b)) echo $a / $b =$(($a/$b))
指令碼執行過程:
[[email protected] scripts]# sh jishuanqi.sh 請輸入第一個整數:12 請輸入第二個整數:12 12 + 12 =24 12 - 12 =0 12 * 12 =144 12 / 12 =1
精簡方法
[[email protected] scripts]# vim jishuanqi2.sh #!/bin/bash ############################################################# # File Name: jishuanqi2.sh # Version: V1.0 # Author: clsn # Organization: http://blog.znix.top # Created Time : 2017-12-06 15:02:41 # Description: ############################################################# echo $(($1))
指令碼執行過程:
[[email protected] scripts]# sh jishuanqi2.sh 1+1 2 [[email protected] scripts]# sh jishuanqi2.sh 1*9 9
1.8.3.2 【練習題】列印結果1+2+3+4+5+6+7+8+9+10=55
指令碼內容
[[email protected] scripts]# vim yunshuan.sh #!/bin/bash ############################################################# # File Name: yunshuan.sh # Version: V1.0 # Author: clsn # Organization: http://blog.znix.top # Created Time : 2017-12-06 09:40:31 # Description: ############################################################# Num=`seq -s + 1 10` echo $Num=$(($Num))
指令碼執行結果
[[email protected] scripts]# sh yunshuan.sh 1+2+3+4+5+6+7+8+9+10=55
1.9 補充說明
shell指令碼中批量註釋的方法
<<'EOF' 檔案內容 EOF 或 使用 exit可以註釋其之後的所有內容(類似註釋,實質為不執行後面的內容)
2.1 條件表示式
2.1.1 檔案判斷
常用檔案測試操作符
常用檔案測試操作符 |
說明 |
-d檔案,d的全拼為directory |
檔案存在且為目錄則為真,即測試表達式成立 |
-f檔案,f的全拼為file |
檔案存在且為普通檔案則為真,即測試表達式成立 |
-e檔案,e的全拼為exist |
檔案存在則為真,即測試表達式成立。注意區別於“-f”,-e不辨別是目錄還是檔案 |
-r檔案,r的全拼為read |
檔案存在且可讀則為真,即測試表達式成立 |
-s檔案,s的全拼為size |
檔案存在且檔案大小不為0則為真,即測試表達式成立 |
-w檔案,w的全拼為write |
檔案存在且可寫則為真,即測試表達式成立 |
-x檔案,x的全拼為executable |
檔案存在且可執行則為真,即測試表達式成立 |
-L檔案,L的全拼為link |
檔案存在且為連結檔案則為真,即測試表達式成立 |
fl -nt f2,nt 的全拼為 newer than |
檔案fl比檔案f2新則為真,即測試表達式成立。根據檔案的修改時間來計算 |
fl -ot f2,ot 的全拼為 older than |
檔案fl比檔案f2舊則為真,即測試表達式成立。根據檔案的修改時間來計算 |
判斷檔案是否存在
[[email protected] scripts]# [ -f /etc/hosts ] [[email protected] scripts]# echo $? 0 [[email protected] scripts]# [ -f /etc/hosts1 ] [[email protected] scripts]# echo $? 1
判斷檔案是否存在,返回方式
[[email protected] scripts]# [ -f /etc/hosts ] && echo "檔案存在" || echo "檔案不存在" 檔案存在 [[email protected] scripts]# [ -f /etc/hosts1 ] && echo "檔案存在" || echo "檔案不存在" 檔案不存在
判斷目錄是否存在
[[email protected] scripts]# [ -d /tmp ] && echo "目錄存在" || echo "目錄不存在" 目錄存在 [[email protected] scripts]# [ -d /tmp1 ] && echo "目錄存在" || echo "目錄不存在" 目錄不存在
使用變數的方法進行判斷
dir=/etc1/;[ -d $dir ] && tar zcf etc.tar.gz $dir || echo "$dir目錄不存在"
2.1.2 字串判斷
字串測試操作符
常用字串測試操作符 |
說明 |
-n "字串" |
若字串的長度不為0,則為真,即測試表達式成立,n可以理解為no zero |
-Z "字串" |
若字串的長度為0,則為真,即測試表達式成立,z可以理解為zero的縮寫 |
"串 1"== "串 2" |
若字串1等於字串2,則為真,即測試表達式成立,可使用"=="代替"=" |
"串 1" != "串 2" |
若字串1不等於字串2,則為真,即測試表達式成立,但不能用"!=="代替"!=" |
1.對於字串的測試,一定要將字串加雙引號之後再進行比較。 2.空格非空 |
-z 判斷字串長度
[[email protected] scripts]# x= ; [ -z "$x" ] && echo "輸入為空" || echo '輸入有內容' 輸入為空 [[email protected] scripts]# x=12 ; [ -z "$x" ] && echo "輸入為空" || echo '輸入有內