Linux(8):linux三劍客sed和awk & Shell 編程(1)

linux 三劍客 之 sed

# sed 是什麼?
# sed : 字符流編輯器 Stream Editor; sed 擅長 替換、取行等

# sed 的功能與版本:
    處理純文本文件、日誌、配置文件等 
    增長、刪除、修改、查詢
    sed --version  # 查看 sed 版本
    
# sed 語法格式:
    sed [選項] [sed指令] [輸入文件]
    sed -i.bak 's#oldboy#oldgirl#g' oldboy.txt        # -i --- sed命令的參數 ;sed --- sed命令,一個指令 ;g    --- 小尾巴, 修飾

sed 命令的執行流程

模式空間: sed 從文件讀取一行文件後存入的緩衝區 (這個緩衝區是在內存中的)html

 

sed 經常使用功能:

1. 查詢
2. 增長
3. 刪除
4. 替換
5. 拓展

1. sed 經常使用功能之顯示 p (print)

# 建立測試環境:
cat>person.txt<<EOF
101,oldboy,CEO
102,zhangyao,CTO
103,Alex,COO
104,yy,CFO
105,feixue,CIO
EOF

# cat>...<<EOF...EOF  表示建立文件 ; cat>>...<<EOF...EOF 表示向文件中追加內容

[root@NEO oldboy]# cat person.txt 
101,oldboy,CEO
102,zhangyao,CTO
103,Alex,COO
104,yy,CFO
105,feixue,CIO
[root@NEO oldboy]# 

# 1.1 顯示某一行    
[root@NEO oldboy]# sed -n '3p' person.txt     # -n 表示 取消默認輸出; '3p' 表示顯示第3行
103,Alex,COO
    
# 1.2 顯示連續多行文本
# 顯示第2行到第4行的內容,包含第2行和第4行
[root@NEO oldboy]#  sed -n '2,4p' person.txt     # '2,4p' 表示顯示從第2行到第4行
102,zhangyao,CTO
103,Alex,COO
104,yy,CFO

# 1.3 顯示包含 oldboy 的行到 包含104的行
[root@NEO oldboy]# sed -n '/oldboy/p' person.txt     # '/oldboy/p' ---> 表示 包含 oldboy 的行 ;此時 該行命令 至關於 grep 'oldboy',但 grep 不能過濾範圍
101,oldboy,CEO
[root@NEO oldboy]# sed -n '/oldboy/,/104/p' person.txt         # '/oldboy/,/104/p' ---> 包含 oldboy 的行 到 包含 104 的行
101,oldboy,CEO
102,zhangyao,CTO
103,Alex,COO
104,yy,CFO
[root@NEO oldboy]# sed -n '/oldboy/,/^104/p' person.txt     # '/oldboy/,/^104/p' ---> 表示從包含 oldboy 的行到 以104開頭的行
101,oldboy,CEO
102,zhangyao,CTO
103,Alex,COO
104,yy,CFO


# 1.4 過濾多個字符串
# 默認狀況下,sed只支持基本正則表達式;sed 的 -r 參數,能夠支持 擴展正則表達式 (| 和 ())
# 顯示包含 oldboy 的行 或者 yy 的行
[root@NEO oldboy]# egrep 'oldboy|yy' person.txt 
101,oldboy,CEO
104,yy,CFO
[root@NEO oldboy]# sed -rn '/oldboy|yy/p' person.txt     # -r '/oldboy|yy/p' ---> 表示 包含 oldboy 或者 yy 的行
101,oldboy,CEO
104,yy,CFO

# sed 命令經過正則表達式進行過濾時,至關於 egrep 


# 1.5 查詢指定多行
[root@NEO oldboy]# sed -n '1p;3p' person.txt     #  '1p;3p' ---> 第1行 和 第3行; 多行之間用 逗號 分隔
101,oldboy,CEO
103,Alex,COO
[root@NEO oldboy]# sed -n '1p;2,4p;5p' person.txt     # , 和 ; 搭配使用
101,oldboy,CEO
102,zhangyao,CTO
103,Alex,COO
104,yy,CFO
105,feixue,CIO
[root@NEO oldboy]# sed -n '/oldboy/p;3,5p' person.txt 
101,oldboy,CEO
103,Alex,COO
104,yy,CFO
105,feixue,CIO

2. sed 經常使用功能之增長

# 2.1 單行增長:
# 在第3行後面增長一行內容
[root@NEO oldboy]# cat person.txt 
101,oldboy,CEO
102,zhangyao,CTO
103,Alex,COO
104,yy,CFO
105,feixue,CIO
[root@NEO oldboy]# sed '3a 103.5,Lee,UFO' person.txt     # 3a 表示在第3行的後面增長一行內容,3a 後面的空格沒有用,也能夠不寫
101,oldboy,CEO
102,zhangyao,CTO
103,Alex,COO
103.5,Lee,UFO
104,yy,CFO
105,feixue,CIO[root@NEO oldboy]# cat person.txt     # sed '3a ' 命令並無真正修改文件內容,若是想要真正修改文件內容,能夠用 sed 的 -i 參數
101,oldboy,CEO
102,zhangyao,CTO
103,Alex,COO
104,yy,CFO
105,feixue,CIO
[root@NEO oldboy]# sed '3i 103.5,Lee,UFO' person.txt     # 3i 表示在第3行的前面再增長一行內容;同理, 該命令也沒有真正修改文件內容,想要真正修改文件內容也是加上 -i 參數
101,oldboy,CEO
102,zhangyao,CTO
103.5,Lee,UFO
103,Alex,COO
104,yy,CFO
105,feixue,CIO

# 增長單選文本:
    a 參數 :追加 append,在指定行後添加一行或多行文本
    i 參數 :插入 insert,在指定行前添加一行或多行文本

# 在最後一行插入:
[root@NEO oldboy]# sed -n '$p' person.txt     # 在 sed 命令中, $ 表示最後一行
105,feixue,CIO
[root@NEO oldboy]# sed  '$a 103.5,Lee,UFO' person.txt     # 在最後一行插入一行內容
101,oldboy,CEO
102,zhangyao,CTO
103,Alex,COO
104,yy,CFO
105,feixue,CIO
103.5,Lee,UFO
[root@NEO oldboy]# sed  '$a new,new,new\nold,old,old' person.txt     # 在最後一行增長多行內容,用 \n 分隔 (這種方法不經常使用;此命令已被 cat>>...<<EOF...EOF 替代,並且在最後一行的多行追加通常用 cat>> 方法)
101,oldboy,CEO
102,zhangyao,CTO
103,Alex,COO
104,yy,CFO
105,feixue,CIO
new,new,new
old,old,old

3. sed 經常使用功能之刪除

# 去除空行實戰:刪除最後一行
[root@NEO oldboy]# cat person.txt 
101,oldboy,CEO
102,zhangyao,CTO
103,Alex,COO
104,yy,CFO
105,feixue,CIO
[root@NEO oldboy]# sed '$d' person.txt     # 刪除最後一行
101,oldboy,CEO
102,zhangyao,CTO
103,Alex,COO
104,yy,CFO
[root@NEO oldboy]# sed '1,3d' person.txt  # 刪除第1行到第3行; d 表示 delete 
104,yy,CFO
105,feixue,CIO
    
# 企業案例:不顯示文件中空行
[root@NEO oldboy]# vim person.txt 
[root@NEO oldboy]# cat -nA person.txt     # cat 的 -n 參數表示顯示 行號, -A 表示 顯示結尾的 $
     1    101,oldboy,CEO$
     2    102,zhangyao,CTO$
     3    $
     4    103,Alex,COO$
     5    $
     6    104,yy,CFO$
     7    $
     8    105,feixue,CIO$
[root@NEO oldboy]# grep -v '^$' person.txt     # grep -v 表示 排除
101,oldboy,CEO
102,zhangyao,CTO
103,Alex,COO
104,yy,CFO
105,feixue,CIO
[root@NEO oldboy]# sed '/^$/d' person.txt     # sed 的 /^$/ 表示空行
101,oldboy,CEO
102,zhangyao,CTO
103,Alex,COO
104,yy,CFO
105,feixue,CIO
    
# 另外一種方法: sed 的 ! 表示 取反; 在 p d 這些參數前面加 !
[root@NEO oldboy]# sed -n '/^$/p' person.txt     # 顯示空行



[root@NEO oldboy]# sed -n '/^$/!p' person.txt     # 排除空行
101,oldboy,CEO
102,zhangyao,CTO
103,Alex,COO
104,yy,CFO
105,feixue,CIO
[root@NEO oldboy]# 
[root@NEO oldboy]# sed '$!d' person.txt     # '$!d' : 不刪除最後一行
105,feixue,CIO

4. sed經常使用功能之替換

# 文本替換: sed -i 's#neo#NEO#g' oldboy.log      
    # s 單獨使用 ---> 將每一行中 第一處匹配的字符串進行替換
    # g (global:全局) ---> 每一行進行所有替換 --> sed 指令 s 的替換標誌之一(全局替換)
    # sed 的 -i 參數 ---> 用於修改文件; -i.ori ---> 自動備份;先備份源文件,而後修改文件的內容
    
[root@NEO oldboy]# cat person.txt 
101,oldboy,CEO
102,zhangyao,CTO

103,Alex,COO

104,yy,CFO

105,feixue,CIO
[root@NEO oldboy]# sed 's#o#AAAA#' person.txt 
101,AAAAldboy,CEO
102,zhangyaAAAA,CTO

103,Alex,COO

104,yy,CFO

105,feixue,CIO
[root@NEO oldboy]# sed 's#o#AAAA#g' person.txt 
101,AAAAldbAAAAy,CEO
102,zhangyaAAAA,CTO

103,Alex,COO

104,yy,CFO

105,feixue,CIO

5. sed變量替換 (重點)

[root@NEO oldboy]# x=oldboy        # oldboy 賦值給 x
[root@NEO oldboy]# y=oldgirl    # oldgirl 賦值給 y (中間不要有空格)
[root@NEO oldboy]# sed 's#$x#$y#g' person.txt   # '' ---> 所見即所得,因此 '' 中的內容沒有被解析
101,oldboy,CEO
102,zhangyao,CTO

103,Alex,COO

104,yy,CFO

105,feixue,CIO
[root@NEO oldboy]# sed "s#$x#$y#g" person.txt         # "" 中的特殊符號($ $() `` !)會被解析 ; $x 表示 x變量  
101,oldgirl,CEO
102,zhangyao,CTO

103,Alex,COO

104,yy,CFO

105,feixue,CIO
    
    
# sed 的反向引用 :參考之前的    
    

 

linux 三劍客 之 awk  --- 取列、取行、統計

1. 基本的awk 執行過程:

取出 passwd 文件的第二行的第一列和第二列

[root@NEO ~]# head -2 /etc/passwd
root:x:0:0:root:/root:/bin/bash
bin:x:1:1:bin:/bin:/sbin/nologin
[root@NEO ~]# awk -F ":" 'NR==2{print $1,$2}' /etc/passwd
bin x

# awk 語法格式:
# awk 參數 '模式{動做}' 文件   --->  awk 參數 '條件(找誰){幹啥}' 文件

2. 模式匹配:模式與動做

# 經過正則表達式做爲模式
# awk 使用正則表達式做爲模式

# 建立環境:
mkdir -p /server/files/
cat >>/server/files/reg.txt<<EOF
Zhang Dandan    41117397   :250:100:175
Zhang Xiaoyu    390320151  :155:90:201
Meng  Feixue    80042789   :250:60:50
Wu    Waiwai    70271111   :250:80:75
Liu   Bingbing  41117483   :250:100:175
Wang  Xiaoai    3515064655 :50:95:135
Zi    Gege      1986787350 :250:168:200
Li    Youjiu    918391635  :175:75:300
Lao   Nanhai    918391635  :250:100:175
EOF
# 第1表表示姓,第2列表示名字,第3列表示ID,第4列表示捐款金額

[root@NEO server]# cat /server/files/reg.txt 
Zhang Dandan    41117397   :250:100:175
Zhang Xiaoyu    390320151  :155:90:201
Meng  Feixue    80042789   :250:60:50
Wu    Waiwai    70271111   :250:80:75
Liu   Bingbing  41117483   :250:100:175
Wang  Xiaoai    3515064655 :50:95:135
Zi    Gege      1986787350 :250:168:200
Li    Youjiu    918391635  :175:75:300
Lao   Nanhai    918391635  :250:100:175
[root@NEO server]#

# 2.1 找出包含 111 的行:
[root@NEO files]# pwd
/server/files
[root@NEO files]# awk '/111/' reg.txt 
Zhang Dandan    41117397   :250:100:175
Wu    Waiwai    70271111   :250:80:75
Liu   Bingbing  41117483   :250:100:175

# 其它的正則表達式的用法在 awk 沒什麼變化,但 ^ 和 $ 在 awk 中不太同樣
    ^    表示 某一列中 以什麼開頭的字符串(以什麼開頭的列) : $3~/^oldboy/  表示 第3列中 以 oldboy 開頭的字符串, ~ 可理解成 包含
    $    表示 某一列中 以什麼結尾的字符串(以什麼結尾的列) : $3~/oldboy$/ 同理

# 2.2 顯示Xiaoyu的姓名和ID號碼
[root@NEO files]# awk '/Xiaoyu/' reg.txt     # 只有模式(由於沒有{});'/Xiaoyu/' 表示包含 Xiaoyu 的行,它至關於 '$0~/Xiaoyu/',即 把一整行看成一列, awk 的 $0 表示把一整行的內容放到了 $0 中(把一整行看成一列)
Zhang Xiaoyu    390320151  :155:90:201
[root@NEO files]# awk '$0~/Xiaoyu/' reg.txt 
Zhang Xiaoyu    390320151  :155:90:201
[root@NEO files]# awk '/Xiaoyu/{print $1,$2,$3}' reg.txt     # /Xiaoyu/ 表示包含 Xiaoyu 的行
Zhang Xiaoyu 390320151
[root@NEO files]# awk '$2~/Xiaoyu/{print $1,$2,$3}' reg.txt     # $2~/Xiaoyu/ 表示 第2列(名字那一列)包含 Xiaoyu 的行
Zhang Xiaoyu 390320151


# 2.3 顯示全部以41開頭的ID號碼的人的全名和ID號碼
[root@NEO files]# awk '$3~/^41/{print $1,$2,$3}' reg.txt     # $3~/^41/  ---> 第3列(ID那一列)以 41 開頭
Zhang Dandan 41117397
Liu Bingbing 41117483

# 2.4 顯示全部ID號碼最後一位數字是1或5的人的全名
[root@NEO files]# awk '$3~/[15]$/{print $1,$2}' reg.txt     # $3~/[15]$/ 表示模式( {}外面的就是模式 ), {print $1,$2} 表示動做
Zhang Xiaoyu
Wu Waiwai
Wang Xiaoai
Li Youjiu
Lao Nanhai


# 2.5 顯示Xiaoyu的捐款,每一個值都以 $ 開頭,如 $520$200$135
# 4. awk 裏面進行替換的方法 --- gsub 函數 : '{gsub(/要找的內容(支持正則)/,"替換成的內容",$列號)}' 
[root@NEO files]# awk '{gsub(/:/,"$",$4)}' reg.txt   # 沒有輸出是由於 awk 沒有默認輸出
[root@NEO files]# awk '{gsub(/:/,"$",$4);print}' reg.txt     # 再加上 ;print  就會有輸出 
Zhang Dandan 41117397 $250$100$175
Zhang Xiaoyu 390320151 $155$90$201
Meng Feixue 80042789 $250$60$50
Wu Waiwai 70271111 $250$80$75
Liu Bingbing 41117483 $250$100$175
Wang Xiaoai 3515064655 $50$95$135
Zi Gege 1986787350 $250$168$200
Li Youjiu 918391635 $175$75$300
Lao Nanhai 918391635 $250$100$175    # 第4列的 : 替換成了 $ 

# gsub(/目標/,"替換爲何",第幾列)
# gsub(/目標/,"替換爲何")  === gsub(/目標/,"替換爲何",$0)  ---> 整行替換
[root@NEO files]# awk '$2~/Xiaoyu/{gsub(/:/,"$",$4);print}' reg.txt 
Zhang Xiaoyu 390320151 $155$90$201
[root@NEO files]# awk '$2~/Xiaoyu/{gsub(/:/,"$",$4);print $4}' reg.txt 
$155$90$201
[root@NEO files]#

# gsub() 是awk 的一個函數 

3. awk 數組 --- 統計與計算

# 特殊模式: BEGIN 和 END 
    BEGIN{}      ---> BEGIN裏面的內容,會在 awk 讀取文件內容以前運行
    # 通常用於測試、計算等
    
    END{}      ---> END裏面的內容,會在 awk 讀取文件的最後一行以後運行 (END很經常使用)
    # 用來顯示最終結果(前面一直在計算,最後END顯示結果)

[root@NEO files]# awk 'BEGIN{print "this is beginning"}'    # 只寫了個BEGIN ,後面就不用接文件了 
this is beginning
[root@NEO files]# awk 'BEGIN{print "this is beginning"} {print NR,$0}' reg.txt     # {print NR,$0}  ---> NR 表示 行號
this is beginning    # BEGIN的內容 
1 Zhang Dandan    41117397   :250:100:175
2 Zhang Xiaoyu    390320151  :155:90:201
3 Meng  Feixue    80042789   :250:60:50
4 Wu    Waiwai    70271111   :250:80:75
5 Liu   Bingbing  41117483   :250:100:175
6 Wang  Xiaoai    3515064655 :50:95:135
7 Zi    Gege      1986787350 :250:168:200
8 Li    Youjiu    918391635  :175:75:300
9 Lao   Nanhai    918391635  :250:100:175


# 統計 /etc/services 文件裏面的空行數量
[root@NEO files]# awk '/^$/{print NR}' /etc/services     # '/^$/{print NR}'
22
266
299
320
326
393
461
474
479
486
494
506
512
518
583
584
[root@NEO files]# awk '/^$/{i=i+1;print i}' /etc/services     # i=i+1 表示 把 i+1 的結果賦值給 i ,每一個增長1,因此這個公式用來統計;i=i+1 也能夠簡寫成 i++ ; i=i+1 和 print 之間用 ; 分隔
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
[root@NEO files]# 

# i=i+1  === i++  --->  用來統計

[root@NEO files]# awk '/^$/{i=i+1}END{print i}' /etc/services     # {i=i+1}END{print i}  ---> i=i+1 是先計算,END{print i} 表示 文件讀取文件最後一行後 執行 {print i}
16
[root@NEO files]# awk '/^$/{i++}END{print i}' /etc/services     # i++ 至關於 i=i+1
16

awk 數組案例詳解與awk總結

#awk數組-統計與計算

# awk 數組的組成:
    hotel[110]="張三"    
    # hotel 表示 數組的名字(酒店名稱), 110 表示數組的元素名稱(房間號), 張三 表示 元素內容(房間內容) ; hotel[110] 組成了一個數組

[root@NEO files]# awk 'BEGIN{hotel[110]="NEO";hotel[114]="XO";print hotel[110],hotel[114]}'        # 110]="NEO" ---> 建立數組;print hotel[110]  ---> 把數組中的內容顯示出來
NEO XO


# 處理如下文件內容,將域名取出並根據域名進行計數排序處理:(百度和sohu面試題)
http://www.etiantian.org/index.html
http://www.etiantian.org/1.html
http://post.etiantian.org/index.html
http://mp3.etiantian.org/index.html
http://www.etiantian.org/3.html
http://post.etiantian.org/2.html
    
    
    
[root@NEO files]# cat url.txt 
http://www.etiantian.org/index.html
http://www.etiantian.org/1.html
http://post.etiantian.org/index.html
http://mp3.etiantian.org/index.html
http://www.etiantian.org/3.html
http://post.etiantian.org/2.html
[root@NEO files]# awk -F "[/.]+" '{print $2}' url.txt     # 讓 $2 做爲數組的元素
www
www
post
mp3
www
post    
    
# h[$2]  表示 把 第2列(www post mp3)做爲元素名稱組成一個數組;一共有 3個元素
# h[$2]++ 表示 每一個元素名稱 遇到相同的元素名稱時 加1,遇到不一樣的元素名稱時不作處理
# h["www"] 表示 www 這個元素名稱中的 元素內容
    
[root@NEO files]# awk -F "[/.]+" '{h[$2]=h[$2]+1;print h["www"]}' url.txt 
1
2
2
2
3
3
[root@NEO files]# 
    
# 顯示全部元素的內容
[root@NEO files]# awk -F "[/.]+" '{h[$2]++}END{print h["www"],h["post"],h["mp3"]}' url.txt 
3 2 1

# awk 本身提供的循環,可用於顯示數組裏面的內容: for(pol in h) ---> h是數組,pol 是h數組中的變量(數組的元素名稱;遍歷的也是數組的元素)
[root@NEO files]# awk -F "[/.]+" '{h[$2]++}END{for(pol in h) print pol}' url.txt 
www
mp3
post    # 遍歷的是 數組的元素名稱
    
[root@NEO files]# awk -F "[/.]+" '{h[$2]++}END{for(pol in h) print h[pol]}' url.txt     # 把 元素名稱 放到 數組h中
3
1
2
[root@NEO files]# awk -F "[/.]+" '{h[$2]++}END{for(pol in h) print pol,h[pol]}' url.txt 
www 3
mp3 1
post 2

 

shell編程基礎:

shell編程所需的基礎知識:

熟練使用 vim 編輯器
熟練 SSH終端
熟練掌握 Linux經常使用命令
熟練掌握Linux正則表達式及三劍客命令(grep sed awk)

shell編程基礎知識與環境

基礎知識:

# 1. 什麼是Shell ?
# 命令解釋器; 你輸入的命令,誰來給你解釋/運行
# CentOS默認的 Shell 是 bash :
    echo $SHELL
    /etc/passwd
    .sh 結尾的文件
    file 命令也能夠查看文件類型
    
[root@NEO ~]# echo $SHELL
/bin/bash
[root@NEO ~]# cat /etc/shells 
/bin/sh
/bin/bash
/sbin/nologin
/bin/dash
/bin/tcsh
/bin/csh
[root@NEO ~]# file /etc/init.d/iptables 
/etc/init.d/iptables: POSIX shell script text executable  # shell script ---> shell腳本
    
# 2. 什麼是Shell腳本?
    # 命令大禮包 --- 一個程序文件,包含若干行Linux命令語句
    # 循環,條件語句
    
# 建立shell腳本:
# 1. 統一腳本存放目錄
        # 如: /server/scripts/
        
# 2. 推薦使用 vim 編輯器編程腳本
        # 由於 vim 自帶顏色
# 3. 第一行指出由哪一個解釋器來執行腳本中的內容:
        #!/bin/bash ---> #! 稱爲幻數,能被內核識別
                    ---> 必須寫在第一行,若是不是第一行則爲腳本註釋行
                    ---> 雙能夠寫爲  #!/bin/sh
# 4. 版權聲明
# 5. 寫一個簡單腳本(切換目錄顯示文件屬性)並運行


# 腳本目錄示例:
[root@NEO ~]# 
[root@NEO ~]# ls -l /server/scripts/
total 8
-rw-r--r-- 1 root root 66 Apr  7 23:22 ip.sh
-rw-r--r-- 1 root root  9 Apr  7 14:30 show_date.sh


# 腳本註釋 & 版權聲明:
[root@NEO ~]# vim /server/scripts/ip.sh
[root@NEO ~]# cat /server/scripts/ip.sh 
#!/bin/bash                        #!/bin/bash 表示 這個腳本是用 /bin/bash 運行解釋的
# desc:           show ip address
# author:      neo
# time:        20190416
# version:     v1.0

/sbin/ifconfig eth0 |awk -F "[ :]+" 'NR==2{print $4}'
[root@NEO ~]# file /server/scripts/ip.sh 
/server/scripts/ip.sh: Bourne-Again shell script text executable
[root@NEO ~]# /server/scripts/ip.sh        # 正常運行腳本的方法:經過絕對路徑
-bash: /server/scripts/ip.sh: Permission denied        # 在linux 中建立的文件默認的權限是 644
[root@NEO ~]# sh /server/scripts/ip.sh        # 之後在執行腳本的時候都是運行 sh 命令
10.0.0.200

變量

# 3.1 什麼是變量?
    # 用一個固定的字符串,替代更多更復雜的內容
    # x=1
    # devPath=/server/
    # filelist=`ls` 或 $(ls)
    # 引用變量: $x 至關於 ${x}
    
[root@NEO ~]# echo $PATH $LANG        # 環境變量
/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin:/root/bin en_US.UTF-8
[root@NEO ~]# x=1        # 往變量中放值 ; x 是普通變量(局部變量)
[root@NEO ~]# echo $x    # 取出變量中的值
1
[root@NEO ~]# 

# 3.2 變量的分類:
# 3.2.1 局部變量(普通變量):
    只能在建立它們的Shell函數或Shell腳本中使用
    定義變量:
        變量名=value
        變量名要求:
            字母、數字、下劃線組成,必須以字母或下劃線開頭
            規範的變量名寫法定義:見名知意
            駝峯語法:首個單詞字母小寫,其他單詞首字母大寫 ---> oldAgeSex=1
        把一個命令做爲變量
        普通字符串定義測試

[root@NEO ~]# week=10
[root@NEO ~]# echo $weekday        # 此時系統認爲 weekday 這個總體是個變量

[root@NEO ~]# echo ${week}day    # $week 就至關於 ${week}
10day
[root@NEO ~]#

# 3.2.2 全局變量(環境變量):
    大寫,在Linux中絕大地方均可以用
    在建立他們的Shell及其派生出來的子Shell中使用
    分類:
        查看全局變量: env ---> 只顯示全局變量
        bash內置的環境變量:
            Shell經過環境變量來肯定 登錄用戶名、命令路徑、終端類型、登錄日誌等
            LANG PAHT SEHLL UID 等
        自定義環境變量:
            建議全部環境變量名均爲大寫
            必須用 export 命令定義
            取消變量: unset 
            永久生效
            

[root@NEO ~]# echo $LANG $PATH $PS1
en_US.UTF-8 /usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin:/root/bin [\u@\h \W]\$
[root@NEO ~]# 

# 全局變量 和 局部變量
[root@NEO ~]# vim /server/scripts/show_date.sh
[root@NEO ~]# cat /server/scripts/show_date.sh
#!/bin/hash
# desc:
# author:
# time:
# version:

echo $OLDBOY
[root@NEO ~]# OLDBOY=10        # 此時的 OLDBOY 是一個普通變量,在 /server/scripts/show_date.sh  這個腳本中沒法使用
[root@NEO ~]# echo $OLDBOY 
10
[root@NEO ~]# sh /server/scripts/show_date.sh      # 輸出爲空,由於 OLDBOY 是個局部變量,在 這個腳本中沒法使用

[root@NEO ~]# # 讓普通變量變成全局問題的方法: export 命令; export 是臨時生效;取消全局問題的方法 : unset 命令, unset 不但能取消全局變量,也能取消局部變量
[root@NEO ~]# export OLDBOY        # 讓 OLDBOY 這個普通變量 變成 全局變量
[root@NEO ~]# sh /server/scripts/show_date.sh  
10        # 此時 OLDBOY 就能在 該腳本中使用了
[root@NEO ~]# 
[root@NEO ~]# env |grep OLDBOY
OLDBOY=10
[root@NEO ~]# unset OLDBOY
[root@NEO ~]# env |grep OLDBOY
[root@NEO ~]# 


# 3.2.3 Shell 編程之環境變量相關的文件和目錄:
    全局環境變量配置文件:
        /etc/profile    ---> 修改環境變量的文件
        /etc/bashrc
        /etc/profile.d/   ---> 用戶登錄到系統 會運行這個目錄下面的腳本 ;腳本要有執行權限
    用戶本身的環境變量配置文件:
        ~/.bash_profile
        ~/.bashrc

# 修改 /etc/profile.d/ 下的文件 ---> 用戶登錄到系統會自動運行
[root@NEO ~]# ls /etc/profile.d/
colorls.csh  cvs.csh  glib2.csh  lang.csh  less.csh  vim.csh  which2.sh
colorls.sh   cvs.sh   glib2.sh   lang.sh   less.sh   vim.sh
[root@NEO ~]# vim /etc/profile.d/show.sh
[root@NEO ~]# cat /etc/profile.d/show.sh
#!/bin/bash
# desc: show ip address of eth0
# author: neo
# time: 20190417
# version: v1.0

ip a s eth0
[root@NEO ~]# ll /etc/profile.d/show.sh
-rw-r--r-- 1 root root 104 Apr 17 02:00 /etc/profile.d/show.sh
[root@NEO ~]# chmod +x /etc/profile.d/show.sh
[root@NEO ~]# ll /etc/profile.d/show.sh
-rwxr-xr-x 1 root root 104 Apr 17 02:00 /etc/profile.d/show.sh


WARNING! The remote SSH server rejected X11 forwarding request.
Last login: Tue Apr 16 20:48:25 2019 from 10.0.0.1
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP qlen 1000
    link/ether 00:0c:29:26:b5:57 brd ff:ff:ff:ff:ff:ff
    inet 10.0.0.200/24 brd 10.0.0.255 scope global eth0
    inet6 fe80::20c:29ff:fe26:b557/64 scope link 
       valid_lft forever preferred_lft forever
[root@NEO ~]# 

# 本身寫的跳板機放到 /etc/profile.d/ 下面


# 特殊變量:
    # 位置變量:
        $0    (在腳本中)
            獲取當前執行的shell腳本的文件名
            若是執行腳本帶路徑那麼就包括腳本路徑
            模擬系統腳本使用 $0
            
        $n    n 表示數字;$n 表示 第n個參數
        $#    表示參數的個數
    # 進程狀態變量
        $?  ---> 顯示上一個命令的執行結果;命令執行正確 ---> 結果爲0 , 命令執行錯誤 ---> 結果非0 ;軟件安裝後可用 $? 判斷是否安裝成功
        

# 位置變量:
# 環境建立:
[root@NEO scripts]# vim show_args.sh
[root@NEO scripts]# cat show_args.sh 
#!/bin/bash
# desc: 
# author: neo
# time: 
# version:

echo '$0:'$0 '$1:'$1 '$2:'$2 '$3:'$3 '$#:'$#    # '$0:' 須要用單引號,雙引號的話就被解析了
[root@NEO scripts]# sh show_args.sh
$0:show_args.sh $1: $2: $3: $#:0        # $0 表示腳本的名字; $n 在腳本中表示第n個參數
[root@NEO scripts]# sh show_args.sh arg1 arg2 arg3 arg4 arg5 arg6    # 腳本後面能夠跟參數
$0:show_args.sh $1:arg1 $2:arg2 $3:arg3 $#:6        # $# 表示參數的個數(腳本中一共有多少個參數)


[root@NEO scripts]# ls /root/alex.oldboy.txt
ls: cannot access /root/alex.oldboy.txt: No such file or directory
[root@NEO scripts]# echo $?
2        # 執行錯誤
[root@NEO scripts]# ls /root/
alex.txt  anaconda-ks.cfg  data  echotest.txt  install.log.syslog  oldboy-20171111.log
[root@NEO scripts]# echo $?
0        # 執行正確
[root@NEO scripts]#


# 變量賦值方法 --- read

# 如何向變量中放內容?
[root@NEO scripts]# vim show_args.sh 
[root@NEO scripts]# cat show_args.sh
#!/bin/bash
# desc: 
# author: neo
# time: 
# version:

x=1
y=2
echo $x $y
[root@NEO scripts]# sh show_args.sh 
1 2

# 若是 x y 是動態的參數,則利用下面的方法
[root@NEO scripts]# vim show_args.sh
[root@NEO scripts]# cat show_args.sh
#!/bin/bash
# desc: 
# author: neo
# time: 
# version:

x=$1    # 改爲 $1 和 $2
y=$2
echo $x $y
[root@NEO scripts]# sh show_args.sh 10 20    # 傳參10和20;10傳給$1 ,20傳給 $2
10 20

# read 可以從命令行中讀取內容放到變量中 (交互式的)
[root@NEO scripts]# read -p "input x y:" x y
input x y:10 20
[root@NEO scripts]# echo $x
10
[root@NEO scripts]# echo $y
20
[root@NEO scripts]# 


[root@NEO scripts]# vim show_args.sh 
[root@NEO scripts]# cat show_args.sh
#!/bin/bash
# desc: 
# author: neo
# time: 
# version:

# x=$1
# y=$2

read -p "input x y:" x y
echo $x $y
[root@NEO scripts]# sh show_args.sh
input x y:30 40
30 40
[root@NEO scripts]# 

 

循環條件:

條件表達式:
    格式:[<測試表達式>] 
        先敲一對 [] ,而後退格輸入2個空格 [  ],最後再回退一個空格開始輸入,即 [] 兩端要各有一個空格,如: [ -f /etc/hosts ]
    判斷文件:
        -f  ---> 文件是否存在
        -d  ---> 目錄是否存在
        0 存在,1 不存在
    判斷整數:
        等於 equal                ---> -eq
        不等於 not equal        ---> -ne
        大於 greater than        ---> -gt
        大於等於 greater euqal    ---> -ge
        小於 less than            ---> -lt
        小於等於 less euqal        ---> -le
    簡單案例

# Shell編程之測試表達式 --- 中括號
# [] 表示判斷或測試
[root@NEO scripts]# [ -f /root/alex.oldboy.txt ]    # 判斷 /root/alex.oldboy.txt 這個文件是否存在 
[root@NEO scripts]# echo $?
1    # 1 表示 [ -f /root/alex.oldboy.txt ] 查找的文件不存在, 0 表示存在
[root@NEO scripts]# [ -f /oldboy/oldboy.txt ]
[root@NEO scripts]# echo $?
0
[root@NEO scripts]# [ -d /root ]    # 判斷 /root 這個目錄是否存在; -d 判斷目錄是否存在 , -f 判斷文件是否存在
[root@NEO scripts]# echo $?
0

# 判斷整數:
[root@NEO scripts]# [ 1 -eq 1 ]
[root@NEO scripts]# echo $?
0

# 判斷整數的簡單案例:判斷命令行參數個數等於2
[root@NEO scripts]# sh ./args.sh 
[root@NEO scripts]# sh ./args.sh a b
arg number is 2
[root@NEO scripts]# 

# 若是 /oldboy 目錄不存在則建立
[root@NEO ~]# [ -d /oldboy ] || mkdir -p /oldboy/   # 命令1 || 命令2 --->  || 表示 命令1不成立 則執行 命令2

# 若是 /root/oldboy.txt 存在則提示文件已經存在
[root@NEO ~]# [ -f /oldboy/oldboy.txt ] && echo file exists
file exists


# Shell編程之 if 判斷
# 單分支條件語句:
    # 語法: if [ 條件 ];then 命令 fi    # [] 中括號兩端要有兩個空格
    # 案例:輸入2個字,比較大小
# 語法:



# if 單分支:
[root@NEO scripts]# vim compare.sh
[root@NEO scripts]# cat compare.sh
#!/bin/bash
# desc: 
# author: neo
# time: 20190418
# version: 1.0

num1=$1
num2=$2
if [ $num1 -gt $num2 ];then
    echo $num1 greater than $num2
fi
[root@NEO scripts]# sh compare.sh 
greater than
[root@NEO scripts]# sh compare.sh 10 20
[root@NEO scripts]# sh compare.sh 20 10
20 greater than 10
[root@NEO scripts]# 

# if 雙分支:
[root@NEO scripts]# cat compare.sh 
#!/bin/bash
# desc: 
# author: neo
# time: 20190418
# version: 1.0

num1=$1
num2=$2
if [ $num1 -gt $num2 ];then
    echo $num1 greater than $num2
else
    echo $num1 less equal $num2
fi
[root@NEO scripts]# sh ./compare.sh 10 20
10 less equal 20
[root@NEO scripts]# sh ./compare.sh 20 10
20 greater than 10
[root@NEO scripts]# sh ./compare.sh 20 10 1 3 2 5 7        # 不足之處:後4個參數無用
20 greater than 10
[root@NEO scripts]# sh ./compare.sh 20
./compare.sh: line 9: [: 20: unary operator expected
20 less equal
[root@NEO scripts]# 

# 參數必須是2個
[root@NEO scripts]# cat compare.sh 
#!/bin/bash
# desc: 
# author: neo
# time: 20190418
# version: 1.0

num1=$1
num2=$2

if [ $# -ne 2 ];then
    echo "Useage:please input 2 numbers:num1 num2"
    exit        # 退出程序
fi

if [ $num1 -gt $num2 ];then
    echo $num1 greater than $num2
else
    echo $num1 less equal $num2
fi
[root@NEO scripts]# sh compare.sh 10
Useage:please input 2 numbers:num1 num2
[root@NEO scripts]# sh compare.sh 10 20 30
Useage:please input 2 numbers:num1 num2
[root@NEO scripts]# 


# if 多分支:
[root@NEO scripts]# cat compare.sh
#!/bin/bash
# desc: 
# author: neo
# time: 20190418
# version: 1.0

num1=$1
num2=$2

if [ $# -ne 2 ];then
    echo "Useage:please input 2 numbers:num1 num2"
    exit
fi

if [ $num1 -gt $num2 ];then
    echo $num1 greater than $num2
elif [ $num1 -lt $num2 ];then
    echo $num1 less equal $num2
else
    echo $num1 equal to $num2
fi
[root@NEO scripts]# 

# shell 不太擅長小數

Shell編程之 for 循環

# for 循環語句:
    # 格式:
        for 變量名字 in 列表
        do
            命令
        done


[root@NEO scripts]# for num in 1 2 3 4 5
> do
> echo "the $num number is:"$num
> done 
the 1 number is:1
the 2 number is:2
the 3 number is:3
the 4 number is:4
the 5 number is:5
[root@NEO scripts]# 


# 優化linux開機啓動項目,只保留 crond,sshd,network,rsyslog,sysstat ,其餘的都關閉
# 思路: chkconfig 服務 off

# 第一步:先排除上面的那幾個服務
[root@NEO scripts]# chkconfig |egrep "crond|sshd|network|rsyslog|sysstat" -v
# 第二步:取出全部的服務名
[root@NEO scripts]# chkconfig |egrep "crond|sshd|network|rsyslog|sysstat" -v|awk '{print $1}'
# for 循環遍歷關閉
[root@NEO scripts]# for service in `chkconfig |egrep "crond|sshd|network|rsyslog|sysstat" -v|awk '{print $1}'`
> do
>     echo chkconfig $service off    # echo 爲了測試
> done
相關文章
相關標籤/搜索