一文喫透 shell 編寫工具及基本法則!
前言
大家好,這裏是浩道 linux,主要給大家分享 linux、python、網絡通信相關的 IT 知識平臺。
今天浩道跟大家分享關於 shell 編程相關的硬核乾貨,通過本文你將喫透 shell 編寫相關工具及基本法則。讓你編寫 shell 腳本如魚得水!
1. 文件處理工具
1.1 grep 工具
行過濾
grep用於根據關鍵字進行行過濾
grep options 'keys' filename
OPTIONS:
-i: 不區分大小寫
-v: 查找不包含指定內容的行,反向選擇
-w: 按單詞搜索
-o: 打印匹配關鍵字
-c: 統計匹配到的次數
-n: 顯示行號
-r: 逐層遍歷目錄查找
-A: 顯示匹配行及後面多少行
-B: 顯示匹配行及前面多少行
-C: 顯示匹配行前後多少行
-l:只列出匹配的文件名
-L:列出不匹配的文件名
-e: 使用正則匹配
-E:使用擴展正則匹配
^key:以關鍵字開頭
key$:以關鍵字結尾
^$:匹配空行
--color=auto :可以將找到的關鍵詞部分加上顏色的顯示
臨時設置:
# alias grep='grep --color=auto' //只針對當前終端和當前用戶生效
永久設置:
1)全局(針對所有用戶生效)
vim /etc/bashrc
alias grep='grep --color=auto'
source /etc/bashrc
2)局部(針對具體的某個用戶)
vim ~/.bashrc
alias grep='grep --color=auto'
source ~/.bashrc
示例:
# grep -i root passwd 忽略大小寫匹配包含root的行
# grep -w ftp passwd 精確匹配ftp單詞
# grep -w hello passwd 精確匹配hello單詞;自己添加包含hello的行到文件中
# grep -wo ftp passwd 打印匹配到的關鍵字ftp
# grep -n root passwd 打印匹配到root關鍵字的行好
# grep -ni root passwd 忽略大小寫匹配統計包含關鍵字root的行
# grep -nic root passwd 忽略大小寫匹配統計包含關鍵字root的行數
# grep -i ^root passwd 忽略大小寫匹配以root開頭的行
# grep bash$ passwd 匹配以bash結尾的行
# grep -n ^$ passwd 匹配空行並打印行號
# grep ^# /etc/vsftpd/vsftpd.conf 匹配以#號開頭的行
# grep -v ^# /etc/vsftpd/vsftpd.conf 匹配不以#號開頭的行
# grep -A 5 mail passwd 匹配包含mail關鍵字及其後5行
# grep -B 5 mail passwd 匹配包含mail關鍵字及其前5行
# grep -C 5 mail passwd 匹配包含mail關鍵字及其前後5行
1.2 cut 工具
列截取
cut用於列截取
-c: 以字符爲單位進行分割。
-d: 自定義分隔符,默認爲製表符。\t
-f: 與-d一起使用,指定顯示哪個區域。
# cut -d: -f1 1.txt 以:冒號分割,截取第1列內容
# cut -d: -f1,6,7 1.txt 以:冒號分割,截取第1,6,7列內容
# cut -c4 1.txt 截取文件中每行第4個字符
# cut -c1-4 1.txt 截取文件中每行的1-4個字符
# cut -c4-10 1.txt
# cut -c5- 1.txt 從第5個字符開始截取後面所有字符
課堂練習:
用小工具列出你當系統的運行級別。5/3
1.3 sort 工具
排序
sort:將文件的每一行作爲一個單位,從首字符向後,依次按ASCII碼值進行比較,最後將他們按升序輸出。
-u :去除重複行
-r :降序排列,默認是升序
-o : 將排序結果輸出到文件中 類似 重定向符號>
-n :以數字排序,默認是按字符排序
-t :分隔符
-k :第N列
-b :忽略前導空格。
-R :隨機排序,每次運行的結果均不同。
示例:
# sort -n -t: -k3 1.txt 按照用戶的uid進行升序排列
# sort -nr -t: -k3 1.txt 按照用戶的uid進行降序排列
# sort -n 2.txt 按照數字排序
# sort -nu 2.txt 按照數字排序並且去重
# sort -nr 2.txt
# sort -nru 2.txt
# sort -nru 2.txt
# sort -n 2.txt -o 3.txt 按照數字排序並將結果重定向到文件
# sort -R 2.txt
# sort -u 2.txt
1.4 uniq 工具
去除連續的重複行
uniq:去除連續重複行
-i: 忽略大小寫
-c: 統計重複行次數
-d:只顯示重複行
# uniq 2.txt
# uniq -d 2.txt
# uniq -dc 2.txt
1.5 tee 工具
tee工具從標準輸入讀取並寫入標準輸出和文件,即:雙向覆蓋重定向<屏幕輸出|文本輸入>
-a 雙向追加重定向
# echo hello world
# echo hello world|tee file1
# cat file1
# echo 999|tee -a file1
# cat file1
1.6 paste 工具
paste工具用於合併文件行
-d:自定義間隔符,默認是tab
-s:串行處理,非並行
[root@server shell01]# cat a.txt
hello
[root@server shell01]# cat b.txt
hello world
888
999
[root@server shell01]# paste a.txt b.txt
hello hello world
888
999
[root@server shell01]# paste b.txt a.txt
hello world hello
888
999
[root@server shell01]# paste -d'@' b.txt a.txt
hello world@hello
888@
999@
[root@server shell01]# paste -s b.txt a.txt
hello world 888 999
hello
1.7 tr 工具
字符轉換:替換,刪除
tr用來從標準輸入中通過替換或刪除操作進行字符轉換;主要用於刪除文件中控制字符或進行字符轉換。
使用tr時要轉換兩個字符串:字符串1用於查詢,字符串2用於處理各種轉換。
語法:
commands|tr 'string1' 'string2'
tr 'string1' 'string2' < filename
tr options 'string1' < filename
-d 刪除字符串1中所有輸入字符。
-s 刪除所有重複出現字符序列,只保留第一個;即將重複出現字符串壓縮爲一個字符串。
a-z 任意小寫
A-Z 任意大寫
0-9 任意數字
[:alnum:] all letters and digits 所有字母和數字
[:alpha:] all letters 所有字母
[:blank:] all horizontal whitespace 所有水平空白
[:cntrl:] all control characters 所有控制字符
\b Ctrl-H 退格符
\f Ctrl-L 走行換頁
\n Ctrl-J 新行
\r Ctrl-M 回車
\t Ctrl-I tab鍵
[:digit:] all digits 所有數字
[:graph:] all printable characters, not including space
所有可打印的字符,不包含空格
[:lower:] all lower case letters 所有小寫字母
[:print:] all printable characters, including space
所有可打印的字符,包含空格
[:punct:] all punctuation characters 所有的標點符號
[:space:] all horizontal or vertical whitespace 所有水平或垂直的空格
[:upper:] all upper case letters 所有大寫字母
[:xdigit:] all hexadecimal digits 所有十六進制數字
[=CHAR=] all characters which are equivalent to CHAR 所有字符
[root@server shell01]# cat 3.txt 自己創建該文件用於測試
ROOT:x:0:0:root:/root:/bin/bash
bin:x:1:1:bin:/bin:/sbin/nologin
daemon:x:2:2:daemon:/sbin:/sbin/nologin
adm:x:3:4:adm:/var/adm:/sbin/nologin
lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
sync:x:5:0:sync:/sbin:/bin/sync
shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown
halt:x:7:0:halt:/sbin:/sbin/halt
mail:x:8:12:mail:/var/spool/mail:/sbin/nologin
uucp:x:10:14:uucp:/var/spool/uucp:/sbin/nologin
boss02:x:516:511::/home/boss02:/bin/bash
vip:x:517:517::/home/vip:/bin/bash
stu1:x:518:518::/home/stu1:/bin/bash
mailnull:x:47:47::/var/spool/mqueue:/sbin/nologin
smmsp:x:51:51::/var/spool/mqueue:/sbin/nologin
aaaaaaaaaaaaaaaaaaaa
bbbbbb111111122222222222233333333cccccccc
hello world 888
666
777
999
# tr -d '[:/]' < 3.txt 刪除文件中的:和/
# cat 3.txt |tr -d '[:/]' 刪除文件中的:和/
# tr '[0-9]' '@' < 3.txt 將文件中的數字替換爲@符號
# tr '[a-z]' '[A-Z]' < 3.txt 將文件中的小寫字母替換成大寫字母
# tr -s '[a-z]' < 3.txt 匹配小寫字母並將重複的壓縮爲一個
# tr -s '[a-z0-9]' < 3.txt 匹配小寫字母和數字並將重複的壓縮爲一個
# tr -d '[:digit:]' < 3.txt 刪除文件中的數字
# tr -d '[:blank:]' < 3.txt 刪除水平空白
# tr -d '[:space:]' < 3.txt 刪除所有水平和垂直空白
小試牛刀
- 使用小工具分別截取當前主機 IP;截取 NETMASK;截取廣播地址;截取 MAC 地址
[root@server shell01]# ifconfig eth0|grep 'Bcast'|tr -d '[a-zA-Z ]'|cut -d: -f2,3,4
10.1.1.1:10.1.1.255:255.255.255.0
[root@server shell01]# ifconfig eth0|grep 'Bcast'|tr -d '[a-zA-Z ]'|cut -d: -f2,3,4|tr ':' '\n'
10.1.1.1
10.1.1.255
255.255.255.0
[root@server shell01]# ifconfig eth0|grep 'HWaddr'|cut -d: -f2-|cut -d' ' -f4
00:0C:29:25:AE:54
# ifconfig eth1|grep Bcast|cut -d: -f2|cut -d' ' -f1
# ifconfig eth1|grep Bcast|cut -d: -f2|tr -d '[ a-zA-Z]'
# ifconfig eth1|grep Bcast|tr -d '[:a-zA-Z]'|tr ' ' '@'|tr -s '@'|tr '@' '\n'|grep -v ^$
# ifconfig eth0|grep 'Bcast'|tr -d [:alpha:]|tr '[ :]' '\n'|grep -v ^$
# ifconfig eth1|grep HWaddr|cut -d ' ' -f11
# ifconfig eth0|grep HWaddr|tr -s ' '|cut -d' ' -f5
# ifconfig eth1|grep HWaddr|tr -s ' '|cut -d' ' -f5
- 將系統中所有普通用戶的用戶名、密碼和默認 shell 保存到一個文件中,要求用戶名密碼和默認 shell 之間用 tab 鍵分割
[root@server shell01]# grep 'bash$' passwd |grep -v '^root'|cut -d: -f1,2,7|tr ':' '\t'
stu1 x /bin/bash
code x /bin/bash
kefu x /bin/bash
kefu1 x /bin/bash
kefu2 x /bin/bash
user01 x /bin/bash
stu2 x /bin/bash
[root@server shell01]# grep bash$ passwd |grep -viE 'root|mysql'|cut -d: -f1,2,7|tr ':' '\t' |tee a.txt
註釋:
-E 匹配擴展正則表達式,|代表或者,是一個擴展正則
2. 編程語言分類
- 編譯型語言:
程序在執行之前需要一個專門的編譯過程,把程序編譯成爲機器語言文件,運行時不需要重新翻譯,直接使用編譯的結果就行了。程序執行效率高,依賴編譯器,跨平臺性差些。如 C、C++
- 解釋型語言:
程序不需要編譯,程序在運行時由 == 解釋器 == 翻譯成機器語言,每執行一次都要翻譯一次。因此效率比較低。比如 Python/JavaScript/ Perl /ruby/Shell 等都是解釋型語言。
/ 語言分類
- 總結:
編譯型語言比解釋型語言 == 速度較快 ==,但是不如解釋型語言 == 跨平臺性好 ==。如果做底層開發或者大型應用程序或者操作系開發一 == 般都用編譯型語言 ==;如果是一些服務器腳本及一些輔助的接口,對速度要求不高、對各個平臺的 == 兼容性有要求 == 的話則一般都用 == 解釋型語言 ==。
3. shell 介紹
總結:
-
==shell 就是人機交互的一個橋樑 ==
-
shell 的種類
[root@MissHou ~]# cat /etc/shells
/bin/sh #是bash shell的一個快捷方式
/bin/bash #bash shell是大多數Linux默認的shell,包含的功能幾乎可以涵蓋shell所有的功能
/sbin/nologin #表示非交互,不能登錄操作系統
/bin/dash #小巧,高效,功能相比少一些
/bin/tcsh #是csh的增強版,完全兼容csh
/bin/csh #具有C語言風格的一種shell,具有許多特性,但也有一些缺陷
-
用戶在終端(終端就是 bash 的接口)輸入命令
|
bash //bash 就是 shell 的一種類型(bash shell)
|
kernel
|
物理硬件等
4. shell 腳本
-
什麼是 shell 腳本?
-
一句話概括
簡單來說就是將需要執行的命令保存到文本中,== 按照順序執行 ==。它是解釋型的,意味着不需要編譯。
-
準確敘述
若干命令 + 腳本的基本格式 + 腳本特定語法 + 思想 = shell 腳本
-
什麼時候用到腳本?
重複化、複雜化的工作,通過把工作的命令寫成腳本,以後僅僅需要執行腳本就能完成這些工作。
①自動化分析處理
②自動化備份
③自動化批量部署安裝
④等等…
-
如何學習 shell 腳本?
-
儘可能記憶更多的命令
-
掌握腳本的標準的格式(指定魔法字節、使用標準的執行方式運行腳本)
-
必須 熟悉掌握 腳本的基本語法(重點)
- 腳本的基本寫法:
#!/bin/bash
//腳本第一行, #!魔法字符,指定腳本代碼執行的程序。即它告訴系統這個腳本需要什麼解釋器來執行,也就是使用哪一種Shell
//以下內容是對腳本的基本信息的描述
# Name: 名字
# Desc:描述describe
# Path:存放路徑
# Usage:用法
# Update:更新時間
//下面就是腳本的具體內容
commands
...
-
腳本執行方法:
-
標準腳本執行方法(建議):(魔法字節指定的程序會生效)
[root@MissHou shell01]# cat 1.sh #!/bin/bash #xxxx #xxx #xxx hostname date [root@MissHou shell01]# chmod +x 1.sh [root@MissHou shell01]# ll total 4 -rwxr-xr-x 1 root root 42 Jul 22 14:40 1.sh [root@MissHou shell01]# /shell/shell01/1.sh MissHou.itcast.cc Sun Jul 22 14:41:00 CST 2018 [root@MissHou shell01]# ./1.sh MissHou.itcast.cc Sun Jul 22 14:41:30 CST 2018
-
非標準的執行方法(不建議):(魔法字節指定的程序不會運作)
[root@MissHou shell01]# bash 1.sh MissHou.itcast.cc Sun Jul 22 14:42:51 CST 2018 [root@MissHou shell01]# sh 1.sh MissHou.itcast.cc Sun Jul 22 14:43:01 CST 2018 [root@MissHou shell01]# [root@MissHou shell01]# bash -x 1.sh
-
hostname
MissHou.itcast.cc -
date
Sun Jul 22 14:43:20 CST 2018-x: 一般用於排錯,查看腳本的執行過程
-n: 用來查看腳本的語法是否有問題注意:如果腳本沒有加可執行權限,不能使用標準的執行方法執行,bash 1.sh
其他:
[root@server shell01]# source 2.sh
server
Thu Nov 22 15:45:50 CST 2018
[root@server shell01]# . 2.sh
server
Thu Nov 22 15:46:07 CST 2018source 和 . 表示讀取文件,執行文件裏的命令
5. bash 基本特性
5.1 命令和文件自動補全
Tab 只能補全命令和文件 (RHEL6/Centos6)
5.2 常見的快捷鍵
^c 終止前臺運行的程序
^z 將前臺運行的程序掛起到後臺
^d 退出 等價exit
^l 清屏
^a |home 光標移到命令行的最前端
^e |end 光標移到命令行的後端
^u 刪除光標前所有字符
^k 刪除光標後所有字符
^r 搜索歷史命令
5.3 常用的通配符(重點)
*: 匹配0或多個任意字符
?: 匹配任意單個字符
[list]: 匹配[list]中的任意單個字符
[!list]: 匹配除list中的任意單個字符
{string1,string2,...}:匹配string1,string2或更多字符串
舉例:
touch file{1..3}
touch file{1..13}.jpg
# ls file*
# ls *.jpg
# ll file?
# ll file?.jpg
# ll file??.jpg
# ll file1?.jpg
# ll file?.jpg
# ll file[1023].jpg
# ll file[0-13].jpg
# ll file1[0-9].jpg
# ll file[0-9].jpg
# ll file?[1-13].jpg
# ll file[1,2,3,10,11,12].jpg
# ll file1{11,10,1,2,3}.jpg
# ll file{1..10}.jpg
# ll file{1...10}.jpg
5.4 bash 中的引號(重點)
- 雙引號 "" : 會把引號的內容當成整體來看待,允許通過符號引用其他變量值 單引號′′: 會把引號的內容當成整體來看待,禁止引用其他變量值,shell 中特殊符號都被視爲普通字符 反撇號‘‘: 反撇號和() 一樣,引號或括號裏的命令會優先執行,如果存在嵌套,反撇號不能用
[root@server dir1]# echo "$(hostname)"
server
[root@server dir1]# echo '$(hostname)'
$(hostname)
[root@server dir1]# echo "hello world"
hello world
[root@server dir1]# echo 'hello world'
hello world
[root@server dir1]# echo $(date +%F)
2018-11-22
[root@server dir1]# echo `echo $(date +%F)`
2018-11-22
[root@server dir1]# echo `date +%F`
2018-11-22
[root@server dir1]# echo `echo `date +%F``
date +%F
[root@server dir1]# echo $(echo `date +%F`)
2018-11-22
變量的定義
1. 變量的分類
-
本地變量:當前用戶自定義的變量。當前進程中有效,其他進程及當前進程的子進程無效。
-
環境變量:當前進程有效,並且能夠被子進程調用。
-
查看當前用戶的環境變量 env
-
查詢當前用戶的所有變量 (臨時變量與環境變量) set
-
export // 將當前變量變成環境變量
[root@MissHou tmp]# export A=hello //臨時將一個本地變量(臨時變量)變成環境變量
[root@MissHou tmp]# env|grep ^A
A=hello
永久生效:
vim /etc/profile 或者 ~/.bashrc
export A=hello
或者
A=hello
export A
說明:系統中有一個變量PATH,環境變量
export PATH=/usr/local/mysql/bin:$PATH
- 全局變量:全局所有的用戶和程序都能調用,且繼承,新建的用戶也默認能調用.
$HOME/.bashrc 當前用戶的bash信息(aliase、umask等)
$HOME/.bash_profile 當前用戶的環境變量()
oracle——>oracle用戶——>$oracle/.bash_profile——>export home_install=/u01/app/xxx
$HOME/.bash_logout 每個用戶退出當前shell時最後讀取的文件
/etc/bashrc 使用bash shell用戶全局變量
grep --color=auto
umask
/etc/profile 系統和每個用戶的環境變量信息
mycat_home=/usr/local/mycat/bin
export mycat_home
執行mycat命令
# mycat
$ mycat
用戶登錄系統讀取相關文件的順序:
/etc/profile——>$HOME/.bash_profile——>$HOME/.bashrc——>/etc/bashrc——>$HOME/.bash_logout
source /etc/bashrc
- 系統變量 (內置 bash 中變量) :shell 本身已經固定好了它的名字和作用.
$?:上一條命令執行後返回的狀態,當返回狀態值爲0時表示執行正常,非0值表示執行異常或出錯
若退出狀態值爲0,表示命令運行成功
若退出狀態值爲127,表示command not found
若退出狀態值爲126,表示找到了該命令但無法執行(權限不夠)
若退出狀態值爲1&2,表示沒有那個文件或目錄
$$:當前所在進程的進程號 echo $$ eg:kill -9 `echo $$` = exit 退出當前會話
$!:後臺運行的最後一個進程號 (當前終端) # gedit &
!$ 調用最後一條命令歷史中的參數
!! 調用最後一條命令歷史
$#:腳本後面接的參數的個數
$*:腳本後面所有參數,參數當成一個整體輸出,每一個變量參數之間以空格隔開
$@: 腳本後面所有參數,參數是獨立的,也是全部輸出
$0:當前執行的進程/程序名 echo $0
$1~$9 位置參數變量
${10}~${n} 擴展位置參數變量 第10個位置變量必須用{}大括號括起來
./1.sh a b c
[root@MissHou shell01]# cat 2.sh
#!/bin/bash
#xxxx
echo "\$0 = $0"
echo "\$# = $#"
echo "\$* = $*"
echo "\$@ = $@"
echo "\$1 = $1"
echo "\$2 = $2"
echo "\$3 = $3"
echo "\$11 = ${11}"
echo "\$12 = ${12}"
瞭解$*和$@的區別:
$* :表示將變量看成一個整體
$@ :表示變量是獨立的
#!/bin/bash
for i in "$@"
do
echo $i
done
echo "======我是分割線======="
for i in "$*"
do
echo $i
done
[root@MissHou shell01]# bash 3.sh a b c
a
b
c
======我是分割線=======
a b c
2. 什麼時候需要定義變量?
-
如果某個內容需要多次使用,並且在代碼中重複出現,那麼可以用變量代表該內容。這樣在修改內容的時候,僅僅需要修改變量的值。
-
在代碼運作的過程中,可能會把某些命令的執行結果保存起來,後續代碼需要使用這些結果,就可以直接使用這個變量。
3. 變量的定義規則
1. 默認情況下,shell裏定義的變量是不分類型的,可以給變量賦與任何類型的值;等號兩邊不能有空格,對於有空格的字符串做爲賦值時,要用引號引起來
變量名=變量值
2. 變量的獲取方式: $變量名 ${變量名}
[root@MissHou shell01]# a=12345678
[root@MissHou shell01]# echo $a
12345678
[root@MissHou shell01]# echo ${a}
12345678
[root@MissHou shell01]# echo ${a:2:3} a表示變量名;2表示從第3個字符開始;3表示後面3個字符
345
如果獲取變量的全部兩個都可以;如果獲取變量的某一部分,用${}
3. 取消變量: unset 變量名
4. 變量名區分大小寫,同名稱但大小寫不同的變量名是不同的變量
5. 變量名可以是字母或數字或下劃線,但是不能以數字開頭或者特殊字符
[root@MissHou shell01]# 1a=hello
-bash: 1a=hello: command not found
[root@MissHou shell01]# ?a=hello
-bash: ?a=hello: command not found
[root@MissHou shell01]# _a=hello
[root@MissHou shell01]# echo $_a
hello
6. 命令的執行結果可以保存到變量
[root@server shell01]# kernel=`uname -r`
[root@server shell01]# echo $kernel
2.6.32-431.el6.x86_64
[root@server shell01]# name=$(uname -n)
[root@server shell01]# echo $name
server.itcast.cc
7. 有類型變量 declare
-i 將變量看成整數
-r 使變量只讀 readonly
-x 標記變量通過環境導出 export
-a 指定爲索引數組(普通數組);查看普通數組
-A 指定爲關聯數組;查看關聯數組
[root@server shell01]# a=10
[root@server shell01]# b=20
[root@server shell01]# echo $a+$b
10+20
[root@server shell01]# declare -i a=2
[root@server shell01]# declare -i b=4
[root@server shell01]# declare -i c=$a+$b
[root@server shell01]# echo $c
6
[root@server shell01]# AAAA=hello
[root@server shell01]# export AAAA
[root@server shell01]# env|grep AAAA
AAAA=hello
[root@server shell01]# declare -x BBBB=hello
[root@server shell01]# env|grep BBBB
BBBB=hello
8. 數組
普通數組:只能使用整數作爲數組索引(元素的下標)
關聯數組:可以使用字符串作爲數組索引(元素的下標)
普通數組定義:用括號來表示數組,數組元素(變量)用“空格”符號分割開。定義數組的一般形式爲:
一次賦一個值:
變量名=變量值
array[0]=v1
array[1]=v2
array[3]=v3
一次賦多個值:
array=(var1 var2 var3 var4)
array1=(`cat /etc/passwd`) //將文件中每一行賦值給array1數組
array2=(`ls /root`)
array3=(harry amy jack "Miss Hou")
array4=(1 2 3 4 "hello world" [10]=linux)
讀取數組:
${array[i]} i表示元素的下標
使用@ 或 * 可以獲取數組中的所有元素:
獲取第一個元素
echo ${array[0]}
echo ${array[*]} 獲取數組裏的所有元素
echo ${#array[*]} 獲取數組裏所有元素個數
echo ${!array[@]} 獲取數組元素的索引下標
echo ${array[@]:1:2} 訪問指定的元素;1代表從下標爲1的元素開始獲取;2代表獲取後面幾個元素
[root@server shell01]# array[0]=var1
[root@server shell01]# array[1]=var2
[root@server shell01]# array[2]=var3
[root@server shell01]# array1=(uu1 uu2 uu3 uu4)
[root@server shell01]# ls
1.sh 2.sh 3.sh 4.sh passwd
[root@server shell01]# array2=(`ls ./`)
[root@server shell01]# array3=(jack harry "Miss Hou" [5]=tom)
查看普通數組信息:
[root@server shell01]# declare -a
declare -a array='([0]="var1" [1]="var2" [2]="var3")'
declare -a array1='([0]="uu1" [1]="uu2" [2]="uu3" [3]="uu4")'
declare -a array2='([0]="1.sh" [1]="2.sh" [2]="3.sh" [3]="4.sh" [4]="passwd")'
declare -a array3='([0]="jack" [1]="harry" [2]="Miss Hou" [5]="tom")'
[root@server shell01]#
[root@server shell01]#
[root@server shell01]# echo ${array[*]}
var1 var2 var3
[root@server shell01]# echo ${array[@]}
var1 var2 var3
[root@server shell01]# echo ${array[2]}
var3
[root@server shell01]# echo ${array2[@]}
1.sh 2.sh 3.sh 4.sh passwd
[root@server shell01]# echo ${array2[3]}
4.sh
[root@server shell01]#
[root@server shell01]# echo ${array2[*]:2:2}
3.sh 4.sh
[root@server shell01]# echo ${#array2[*]}
5
[root@server shell01]# echo ${!array2[*]}
0 1 2 3 4
[root@server shell01]# echo ${!array3[*]}
0 1 2 5
關聯數組定義:
首先聲明關聯數組
declare -A asso_array1
declare -A asso_array2
declare -A asso_array3
數組賦值:
一次賦一個值:
數組名[索引|下標]=變量值
[root@server ~]# asso_array1[linux]=one
[root@server ~]# asso_array1[java]=two
[root@server ~]# asso_array1[php]=three
一次賦多個值:
[root@server ~]# asso_array2=([name1]=harry [name2]=jack [name3]=amy [name4]="Miss Hou")
查看關聯數組:
[root@server ~]# declare -A
declare -A asso_array1='([php]="three" [java]="two" [linux]="one" )'
declare -A asso_array2='([name3]="amy" [name2]="jack" [name1]="harry" [name4]="Miss Hou" )'
[root@server ~]# echo ${asso_array1[linux]}
one
[root@server ~]# echo ${asso_array1[php]}
three
[root@server ~]# echo ${asso_array1[*]}
three two one
[root@server ~]# echo ${!asso_array1[*]}
php java linux
[root@server ~]# echo ${#asso_array1[*]}
3
[root@server ~]# echo ${#asso_array2[*]}
4
[root@server ~]# echo ${!asso_array2[*]}
name3 name2 name1 name4
9. 交互式定義變量的值 read 主要用於讓用戶去定義變量值
-p 提示信息
-n 字符數 (限制變量值的字符數)
-s 不顯示
-t 超時(默認單位秒)(限制用戶輸入變量值的超時時間)
[root@MissHou shell01]# cat 1.txt
10.1.1.1 255.255.255.0
[root@MissHou shell01]# read -p "Input your IP and Netmask:" ip mask < 1.txt
[root@MissHou shell01]# echo $ip
10.1.1.1
[root@MissHou shell01]# echo $mask
255.255.255.0
10. 其他變量(擴展)
1)取出一個目錄下的目錄和文件:dirname和 basename
2)變量"內容"的刪除和替換
一個“%”代表從右往左去掉一個/key/
兩個“%%”代表從右往左最大去掉/key/
一個“#”代表從左往右去掉一個/key/
兩個“##”代表從左往右最大去掉/key/
# A=/root/Desktop/shell/mem.txt
# echo $A
/root/Desktop/shell/mem.txt
# dirname $A 取出目錄
/root/Desktop/shell
# basename $A 取出文件
mem.txt
# url=www.taobao.com
# echo ${#url} 獲取變量的長度
# echo ${url#*.}
# echo ${url##*.}
# echo ${url%.*}
# echo ${url%%.*}
++++++++++++++++++++++++++++++++++++++++++++++++++
以下內容自己完成:
替換:/ 和 //
1015 echo ${url/ao/AO}
1017 echo ${url//ao/AO} 貪婪替換
替代: - 和 :- +和:+
1019 echo ${abc-123}
1020 abc=hello
1021 echo ${abc-444}
1022 echo $abc
1024 abc=
1025 echo ${abc-222}
${變量名-新的變量值} 或者 ${變量名=新的變量值}
變量沒有被賦值:會使用“新的變量值“ 替代
變量有被賦值(包括空值): 不會被替代
1062 echo ${ABC:-123}
1063 ABC=HELLO
1064 echo ${ABC:-123}
1065 ABC=
1066 echo ${ABC:-123}
${變量名:-新的變量值} 或者 ${變量名:=新的變量值}
變量沒有被賦值或者賦空值:會使用“新的變量值“ 替代
變量有被賦值: 不會被替代
1116 echo ${abc=123}
1118 echo ${abc:=123}
[root@server ~]# unset abc
[root@server ~]# echo ${abc:+123}
[root@server ~]# abc=hello
[root@server ~]# echo ${abc:+123}
123
[root@server ~]# abc=
[root@server ~]# echo ${abc:+123}
${變量名+新的變量值}
變量沒有被賦值或者賦空值:不會使用“新的變量值“ 替代
變量有被賦值: 會被替代
[root@server ~]# unset abc
[root@server ~]# echo ${abc+123}
[root@server ~]# abc=hello
[root@server ~]# echo ${abc+123}
123
[root@server ~]# abc=
[root@server ~]# echo ${abc+123}
123
${變量名:+新的變量值}
變量沒有被賦值:不會使用“新的變量值“ 替代
變量有被賦值(包括空值): 會被替代
[root@server ~]# unset abc
[root@server ~]# echo ${abc?123}
-bash: abc: 123
[root@server ~]# abc=hello
[root@server ~]# echo ${abc?123}
hello
[root@server ~]# abc=
[root@server ~]# echo ${abc?123}
${變量名?新的變量值}
變量沒有被賦值:提示錯誤信息
變量被賦值(包括空值):不會使用“新的變量值“ 替代
[root@server ~]# unset abc
[root@server ~]# echo ${abc:?123}
-bash: abc: 123
[root@server ~]# abc=hello
[root@server ~]# echo ${abc:?123}
hello
[root@server ~]# abc=
[root@server ~]# echo ${abc:?123}
-bash: abc: 123
${變量名:?新的變量值}
變量沒有被賦值或者賦空值時:提示錯誤信息
變量被賦值:不會使用“新的變量值“ 替代
說明:?主要是當變量沒有賦值提示錯誤信息的,沒有賦值功能
簡單的四則運算
算術運算:默認情況下,shell 就只能支持簡單的 == 整數 == 運算
+ - * / %(取模,求餘數)
Bash shell 的算術運算有四種方式:
1. 使用 $(( ))
2. 使用$[ ]
3. 使用 expr 外部程式
4. 使用let 命令
注意:
n=1
let n+=1 等價於let n=n+1
思考:能不能用shell做小數運算?
[root@server shell01]# echo 1+1.5|bc
2.5
i++ 和 ++i (瞭解)
對變量的值的影響:
[root@node1 ~]# i=1
[root@node1 ~]# let i++
[root@node1 ~]# echo $i
2
[root@node1 ~]# j=1
[root@node1 ~]# let ++j
[root@node1 ~]# echo $j
2
對錶達式的值的影響:
[root@node1 ~]# unset i j
[root@node1 ~]# i=1;j=1
[root@node1 ~]# let x=i++ 先賦值,再運算
[root@node1 ~]# let y=++j 先運算,再賦值
[root@node1 ~]# echo $i
2
[root@node1 ~]# echo $j
2
[root@node1 ~]# echo $x
1
[root@node1 ~]# echo $y
2
總結:
$(()) $[]
expr 注意空格,*要進行轉義 \
let n+=1 等價 let n=n+1
let n=n**5 n有初值,然後求次冪
i++ ++i
對變量本身沒有影響(自己+1);
表達式中有影響;i++ 先賦值再運算 ++i先運算再賦值
let x=i++ let x=++i
條件判斷
1. 語法格式
-
格式 1:test 條件表達式
-
格式 2:[ 條件表達式 ]
-
格式 3:[[ 條件表達式 ]] 支持正則
說明:
man test 去查看,很多的參數都用來進行條件判斷
2. 條件判斷相關參數
- 與文件存在與否的判斷
-e 是否存在 不管是文件還是目錄,只要存在,條件就成立
-f 是否爲普通文件
-d 是否爲目錄
-S socket
-p pipe
-c character
-b block
-L 軟link
三種語法格式:
test -e file 只要文件存在條件爲真
[ -d /shell01/dir1 ] 判斷目錄是否存在,存在條件爲真
[ ! -d /shell01/dir1 ] 判斷目錄是否存在,不存在條件爲真
[[ -f /shell01/1.sh ]] 判斷文件是否存在,並且是一個普通的文件
-s 判斷文件是否有內容(大小),非空文件條件滿足
說明:-s表示非空,! -s 表示空文件
說明:1.sh文件裏有內容的。
[root@server shell01]# test -s 1.sh
[root@server shell01]# echo $?
0
[root@server shell01]# touch aaa
[root@server shell01]# cat aaa
[root@server shell01]# test -s aaa
[root@server shell01]# echo $?
1
[root@server shell01]# test ! -s aaa
[root@server shell01]# echo $?
0
[root@server shell01]# test ! -s 1.sh
[root@server shell01]# echo $?
1
- 文件權限相關的判斷
-r 當前用戶對其是否可讀
-w 當前用戶對其是否可寫
-x 當前用戶對其是否可執行
-u 是否有suid
-g 是否sgid
-k 是否有t位
- 兩個文件的比較判斷
file1 -nt file2 比較file1是否比file2新
file1 -ot file2 比較file1是否比file2舊
file1 -ef file2 比較是否爲同一個文件,或者用於判斷硬連接,是否指向同一個inode
test file1 -nt file2
[ file1 -ot file2 ]
- 整數之間的判斷
-eq 相等
-ne 不等
-gt 大於
-lt 小於
-ge 大於等於
-le 小於等於
- 字符串之間的判斷
-z 是否爲空字符串 字符串長度爲0,就成立
-n 是否爲非空字符串 只要字符串非空,就是成立
string1 = string2 是否相等
string1 != string2 不等
[root@server shell01]# AAA=hello
[root@server shell01]# BBB=world
[root@server shell01]# test -z $AAA
[root@server shell01]# echo $?
1
[root@server shell01]# test -n $AAA
[root@server shell01]# echo $?
0
[root@server shell01]# [ $AAA = $BBB ]
[root@server shell01]# echo $?
1
[root@server shell01]# [ $AAA != $BBB ]
[root@server shell01]# echo $?
0
- 多重條件判斷
邏輯判斷符號:
-a 和 && (and 邏輯與) 兩個條件同時滿足,整個大條件爲真
-o 和 || (or 邏輯或) 兩個條件滿足任意一個,整個大條件爲真
[ 1 -eq 1 -a 1 -ne 0 ] 整個表達式爲真
[ 1 -eq 1 ] && [ 1 -ne 0 ]
[ 1 -eq 1 -o 1 -ne 1 ] 整個表達式爲真
[ 1 -eq 1 ] || [ 1 -ne 1 ]
[root@server shell01]# [ 1 -eq 0 ] && echo true || echo false
false
[root@server shell01]# [ 1 -eq 1 ] && echo true || echo false
true
&&:前面的表達式爲真
||:前面的表達式爲假
總結:
1、; && ||都可以用來分割命令或者表達式
2、; 完全不考慮前面的語句是否正確執行,都會執行;號後面的內容
3、&& 需要考慮&&前面的語句的正確性,前面語句正確執行纔會執行&&後的內容;反之亦然
make && make install
4、|| 需要考慮||前面的語句的非正確性,前面語句執行錯誤纔會執行||後的內容;反之亦然
5、如果&&和||一起出現,從左往右依次看,按照以上原則
3. 示例
示例:
數值比較:
[root@server ~]# [ $(id -u) -eq 0 ] && echo "the user is admin"
[root@server ~]$ [ $(id -u) -ne 0 ] && echo "the user is not admin"
[root@server ~]$ [ $(id -u) -eq 0 ] && echo "the user is admin" || echo "the user is not admin"
[root@server ~]# uid=`id -u`
[root@server ~]# test $uid -eq 0 && echo this is admin
this is admin
[root@server ~]# [ $(id -u) -ne 0 ] || echo this is admin
this is admin
[root@server ~]# [ $(id -u) -eq 0 ] && echo this is admin || echo this is not admin
this is admin
[root@server ~]# su - stu1
[stu1@server ~]$ [ $(id -u) -eq 0 ] && echo this is admin || echo this is not admin
this is not admin
[stu1@server ~]$
類C風格的數值比較:
注意:在(( ))中,=表示賦值;==表示判斷
1159 ((1==2));echo $?
1160 ((1<2));echo $?
1161 ((2>=1));echo $?
1162 ((2!=1));echo $?
1163 ((`id -u`==0));echo $?
1209 ((a=123));echo $a
1210 unset a
1211 ((a==123));echo $?
字符串比較:
注意:雙引號引起來,看作一個整體;= 和 == 在 [ 字符串 ] 比較中都表示判斷
1196 a='hello world';b=world
1197 [ $a = $b ];echo $?
1198 [ "$a" = "$b" ];echo $?
1199 [ "$a" != "$b" ];echo $?
1200 [ "$a" !== "$b" ];echo $? 錯誤
1201 [ "$a" == "$b" ];echo $?
1202 test "$a" != "$b";echo $?
思考:[ ] 和 [[ ]] 有什麼區別?
1213 a=
1214 test -z $a;echo $?
1215 a=hello
1216 test -z $a;echo $?
1217 test -n $a;echo $?
1217 test -n "$a";echo $?
# [ '' = $a ];echo $?
-bash: [: : unary operator expected
2
# [[ '' = $a ]];echo $?
0
1278 [ 1 -eq 0 -a 1 -ne 0 ];echo $?
1279 [ 1 -eq 0 && 1 -ne 0 ];echo $?
1280 [[ 1 -eq 0 && 1 -ne 0 ]];echo $?
本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源:https://mp.weixin.qq.com/s/yVugthefXRY_e7QmHwA8zQ