一文喫透 shell 編寫工具及基本法則!

前言

大家好,這裏是浩道 linux,主要給大家分享 linuxpython網絡通信相關的 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         刪除所有水平和垂直空白

小試牛刀

  1. 使用小工具分別截取當前主機 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
  1. 將系統中所有普通用戶的用戶名、密碼和默認 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 介紹

總結:

[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,具有許多特性,但也有一些缺陷

4. shell 腳本

  1. 儘可能記憶更多的命令

  2. 掌握腳本的標準的格式(指定魔法字節、使用標準的執行方式運行腳本)

  3. 必須 熟悉掌握 腳本的基本語法(重點)

#!/bin/bash
//腳本第一行, #!魔法字符,指定腳本代碼執行的程序。即它告訴系統這個腳本需要什麼解釋器來執行,也就是使用哪一種Shell

//以下內容是對腳本的基本信息的描述
# Name: 名字
# Desc:描述describe
# Path:存放路徑
# Usage:用法
# Update:更新時間

//下面就是腳本的具體內容
commands
...

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 中的引號(重點)

[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. 變量的分類

[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
$?:上一條命令執行後返回的狀態,當返回狀態值爲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. 語法格式

說明:

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