shell脚本:介绍、语法、运算、流程控制、对文件/输出流处理、案例
文章目錄
- Shell介紹
- shell腳本的命令
- 運行shell腳本
- 特殊符號
- 管道符
- 重定向
- 格式化輸入與輸出
- 格式化輸出
- 運算
- shell數學運算
- 變量
- 數組
- 五大運算
- 循環與流程控制
- if
- for循環
- 循環控制語句
- while循環
- until循環
- case多分支語句
- shell其他知識
- shell函數
- 正則表達式
- 對文件的操作
- 對文件的補充
- 對輸出流處理
- awk命令基本用法
- awk命令高級用法
- awk流程控制與循環
- 腳本案例
- 監控一個主機的存活狀態
- 監控端口存活狀態
- 監控內存使用率
- 使用cpu或內存前十的進程
Shell介紹
shell是一個程序、采用c語言編寫,是用戶和linux內核溝通的橋梁。它既是一種命令語言,又是一種解釋性的編程語言。
內核是管理電腦的所有硬件,同時內核還要負責驅動硬件干活,就比如說我們需要打印一張照片,內核就會驅動打印機去干活。這是內核的兩個主要的功能。用戶下指令給內核,內核再讓相應的硬件設備去干活,但是用戶與內核的語言不通,內核只認識機器語言,而用戶是高級語言,shell的作用就體現在這里了,它就是解釋命令的。
shell功能:
# Shell語法 hell腳本就是將完成一個任務的所有的命令按照執行的先后順序,自上而下寫入到一個文本文件中,然后給予執行權限。
這就是shell腳本的本質,現在做一個案例,編寫一個shell腳本 用來安裝nginx。
我先創建一個shell的文件夾,接下來所有有關shell的練習都在這里面。/home/hs/shell
首先在Nginx的官網中復制一個安裝包的下載鏈接
在練習shell的目錄下創建一個文件vim nginx_install.sh
給文件執行權限
[root@VM-8-7-centos shell_01]# chmod 700 nginx_install.sh然后在執行剛剛創建的shell腳本
[root@VM-8-7-centos shell_01]# pwd /home/hs/shell/shell_01 [root@VM-8-7-centos shell_01]# ls aaa_explain.txt nginx_install.sh [root@VM-8-7-centos shell_01]# ./nginx_install.sh安裝完成之后然后在啟動
# nginx的常用命令 cd /usr/local/nginx/sbin/ ./nginx 啟動 ./nginx -s stop 停止 ./nginx -s quit 安全退出 ./nginx -s reload 重新加載配置文件 ps aux|grep nginx 查看nginx進程然后在通過瀏覽器訪問,就能出現如下界面
shell腳本的命令
文件名盡量見名知意,不要瞎起
在shell腳本的第一行盡量使用#! 寫一段定義腳本的執行環境。#! 在shell中是一個特例,這不是注釋 。 這是定義該shell腳本在哪個環境下執行 寫在第一行
# 表示注釋 在以后的shell腳本執行時,請不要再里面寫中文 即使是注釋也不要寫中文
在定義腳本的執行環境下還需要加一下的提示信息
#!/usr/bin/bash # Author:Hu Shang # Created Time: 2021/8/24 19:27 # Script Description: nginx install script腳本的組成:
- 解釋環境
- 注釋說明
- 執行代碼
運行shell腳本
運行shell腳本有兩種方式:
- 給執行權限
- 使用解釋器直接運行,這種方式就不需要給執行權限了
比如我現在創建一個入門文件,輸入hello world!
vim shell_helloWorld.sh
#!/usr/bin/bash # Author:Hu Shang # created Time: 2021/8/24 19:49 # script Description: shell hello world!!echo "hello world!"我現在可以使用chmod 700 shell_helloWorlf.sh 命令給改文件設置執行權限 然后直接./shell_helloWorld.sh
另一種方式就是:
給該文件不設置執行權限chmod 644 shell_helloWorlf.sh,然后使用
# 先沒有設置執行權限,然后利用bash命令 使用解釋器也可以運行 然后就出現了下面的輸入語句 [root@VM-8-7-centos shell_01]# chmod 644 shell_helloworld.sh [root@VM-8-7-centos shell_01]# bash shell_helloworld.sh hello world!# 處理bash 我還可以使用sh 解釋器來運行shell腳本, 下面六種都支持 但是建議腳本中第一行指定的什么執行環境就使用什么 [root@VM-8-7-centos shell_01]# sh shell_helloworld.sh hello world! [root@VM-8-7-centos shell_01]# cat /etc/shells /bin/sh /bin/bash /usr/bin/sh /usr/bin/bash /bin/tcsh /bin/cshbash -x 文件名 以debug模式運行shell腳本
特殊符號
-
~ 進入到家目錄 比如 cd ~
-
! 執行歷史命令 !! 這是執行上一條命令
-
$ 變量中取內容符 比如我想知到當前用戶是誰echo $USER
-
+ - * / % 對應數學中的加減乘除取余
-
& 后臺執行
-
* 通配符 shell中匹配所有字符
-
? 通配符 shell中匹配除回車之外的單個字符
-
; 如果在一行中需要執行多條命令就需要使用分號
-
| 管道符 上一個命令的輸出作為下一個命令的輸入 例如 cat filename|grep "abc"
-
\ 轉義字符
-
`` 這兩個反引號 作用是在命令中執行命令
[root@VM-8-7-centos ~]# echo -n “date is:”;date +%F date is:2021-08-24 [root@VM-8-7-centos ~]# echo "date is: `date +%F`" date is: 2021-08-24 -
' ' 單引號 腳本中出現的字段可以用單引號引起來 單引號不解釋變量
-
" " 雙引號 腳本中出現的字段可以用雙引號引起來
[root@VM-8-7-centos ~]# echo 'date is: `date +%F`' date is: `date +%F` [root@VM-8-7-centos ~]# echo "date is: `date +%F`" date is: 2021-08-24 # 這就是區別 如果用單引號 那就是原樣輸出 不會去解釋變量
管道符
管道符 | 在shell中是使用的很多的,管道就是上一個命令的輸出作為下一個命令的輸入。
比如我要查看這個文件的內容,命令如下:
[root@VM-8-7-centos shell_01]# cat shell_helloworld.sh #!/usr/bin/bash # Author:Hu Shang # created Time: 2021/8/24 19:49 # script Description: shell hello world!!echo "hello world!"但是如果我不想輸出改文件了,我想把這個通過管道符 輸入給grep 命令 讓改命令檢索某個字符串,
他就會把這段文字中包含某個字符串的這一行內容找出來
[root@VM-8-7-centos shell_01]# cat shell_helloworld.sh | grep "hello world" # script Description: shell hello world!! echo "hello world!"重定向
首先是重定向輸入
# 將haha字符串輸入到test.txt文件中 [root@VM-8-7-centos shell_01]# echo haha > ./test.txt # 但是這個命令是一次性輸入,這條命令會先將文件內容清空,然后進行輸入操作。如果我在使用它輸入其他字符串,就會把上一次輸入的內容替換掉 # 如果我不想清空原來的內容 想進行追加的操作:就需要使用 >> [root@VM-8-7-centos shell_01]# echo haha > test.txt [root@VM-8-7-centos shell_01]# cat test.txt haha [root@VM-8-7-centos shell_01]# echo aaa >> test.txt [root@VM-8-7-centos shell_01]# echo bbb >> test.txt [root@VM-8-7-centos shell_01]# cat test.txt haha aaa bbb接下來是重定向輸出
就比如我使用wc命令來統計一個文件的 行數 單詞數 字節數
[root@VM-8-7-centos shell_01]# wc < ./test.txt 3 3 13這行命令是把這個文件的內容從內容中輸出給 wc 它再進行統計
# 這個統計的是數據流 [root@VM-8-7-centos shell_01]# wc < ./test.txt 3 3 13# 這里統計的是文本 [root@VM-8-7-centos shell_01]# wc ./test.txt 3 3 13 ./test.txt追加輸出
我要寫一個有關與磁盤分區相關的腳本
腳本內容為:
#!/usr/bin/bash # Author: hu shang # Created Time: 2021/8/25 20:57 # Script Description: harddisk partition scriptfdisk /dev/sdb <<EOF n p 3+534M w EOF重定向追加輸出,用 <<
- 然后使用EOF或者是END充當左右括號 將要輸入的內容括起來
- 將我們要交互的內容 頂格寫在EOF中
格式化輸入與輸出
格式化輸出
echo 該命令負責輸出,將內容輸出到默認顯示設備
語法: echo [-n -e] 字符串
echo命令將字符串輸出之后會直接換行
命令選項:
- -n 不要再最后換行
- -e 讓字符串支持轉義字符,如果不加該屬性,字符串中即使有轉義字符也只會把它當成普通字符串輸出
轉義字符:
\a 發出報警
\b 刪除前一個字符
\c 最后不加換行
\f \v 換行,但光標仍停留在原來的位置
\n 換行,且光標移至行首
\r 光標移至當前行首,不會換行
\t 制表位
\nnn 插入nnn(八進制)所代表的ASCII字符
一個輸出倒計時的案例
#!/usr/bin/bash # Author: hushang # Created Time: 2021-08-26 19:00 # Script Description: number downfor time in `seq 9 -1 0`;doecho -n -e "$time"sleep 1echo -n -e "\b" doneecho顏色代碼
讓輸出的字符串加上一些背景顏色 字體顏色
echo -e "\033[背景色;字體顏色m 字符串 \033[字體效果m"# 字符串前后可以沒有空格,如果有的話,輸出也是同樣有空格[root@VM-8-7-centos shell_02]# echo -e "\033[44;31m 你好呀 \033[0m"你好呀
我在最后給輸出的字符串加上了下劃線的選項,導致了下面的命令都有改樣式了,我只需要將最后一個樣式 變為0m 即可
## 格式化輸入 `read` 命令 默認接受鍵盤的輸入,回車符代表輸入結束
當shell腳本執行到read命令時就不會執行了,會停下來
命令選項:
-
-p 打印信息
-
-t 限定時間
read -t5 temp 有輸入就存放在temp變量中,如果五秒中沒有輸入那就不會 一直等待了
-
-s 不回顯, 就比如輸入密碼時 別人就看不到你輸入的內容了
-
-n 輸入字符個數
read -n5 temp 這就是只能輸入五位數,只能識別輸入的五位數,當用戶輸入五位數后程序就自動往下運行了
案例 寫一個簡單的登錄
vim login.sh
#!/usr/bin/bash # Author: hu shang # Created Time: 2021-08-26 20:28 # Script Discrption: test input,loginclear echo -n -e "login: " read echo -n -e "password: " read然后執行該腳本
[root@VM-8-7-centos shell_02]# bash login.sh login: 123 password: 123 [root@VM-8-7-centos shell_02]#但是現在的問題的,我們輸入的內容的確的輸入了,并且放在了內存中,可是并沒有定位,根本不知道存放的位置,也就使用不了,所以需要使用一個邏輯變量名
#!/usr/bin/bash # Author: hu shang # Created Time: 2021-08-26 20:28 # Script Discrption: test input,loginclear echo -n -e "login: " read acc echo -n -e "password: " read passecho "username: $acc password: $pass" # 這里就能將我上面的輸入拿來用了。這其實就是一個變量,變量就是在內存中找一塊位置,做一個定位,定好位后就將我們輸入的內容存到該定位中
我每次都需要使用兩個語句: echo 和 read 這兩個命令可以結合為一條命令 也就是上方的-p 命令參數
#!/usr/bin/bash # Author: hu shang # Created Time: 2021-08-26 20:28 # Script Discrption: test input,loginclear # echo -n -e "login: " # read acc read -p "login: " acc echo -n -e "password: " read passecho "username: $acc password: $pass" # 這里就能將我上面的輸入拿來用了。運算
shell數學運算
expr 這個命令是用來做數學運算的
# 該命令有很嚴格是空格要求 [root@VM-8-7-centos shell_01]# expr 1+1 1+1 # 參與運算的數與運算符之間都需要空格 [root@VM-8-7-centos shell_01]# expr 1 + 1 2 # 參與運算的數必須是整數 [root@VM-8-7-centos shell_01]# expr 1 + 1.1 expr: non-integer argument # 乘法必須轉義 [root@VM-8-7-centos shell_01]# expr 1 * 2 expr: syntax error [root@VM-8-7-centos shell_01]# expr 1 \* 2 2 [root@VM-8-7-centos shell_01]# expr 10 / 2 5 [root@VM-8-7-centos shell_01]# expr 10 % 3 1比如,我要判斷一個數是否為整數
# 可以先讓要判斷的數 +1 [root@VM-8-7-centos shell_01]# expr 8 + 1 9 # $? 是判斷上一條命令是否執行成功,如果是0就表示執行成功 如果是 [root@VM-8-7-centos shell_01]# echo $? 0 # 執行失敗的情況 [root@VM-8-7-centos shell_01]# expr 7 + 7.1 expr: non-integer argument [root@VM-8-7-centos shell_01]# echo $? 2 # 還可以將上一條命令的輸出 不進行輸出 讓它輸出到回收站中去。然后判斷上一條命令是否執行成功 [root@VM-8-7-centos shell_01]# expr 7 + 7.1 &>/dev/null ; echo $? 2數學運算還有另一個命令let ,它必須將結果賦值到一個變量中去,然后進行其他操作
[root@VM-8-7-centos shell_01]# let sum=1+2+3 [root@VM-8-7-centos shell_01]# echo $sum 6let 命令也是整數的運算
但是在shell中難免會出現小數的運算,就可以使用bc 計算器
[root@VM-8-7-centos shell_01]# bc bc 1.06.95 Copyright 1991-1994, 1997, 1998, 2000, 2004, 2006 Free Software Foundation, Inc. This is free software with ABSOLUTELY NO WARRANTY. For details type `warranty'. 1+1 213-11 24/2 23*3 9# 但是bc計算器默認也不支持小數運算,需要使用下面的命令指定一個小數位,然后就可以執行小數運算了 scale=2 10/3 3.33但bc 計算器是一個交互界面,shell腳本中不能交互,這就用到了管道
[root@VM-8-7-centos shell_01]# echo "scale=2;10/4" | bc 2.50[root@VM-8-7-centos shell_01]# echo "百分數:`echo "scale=2;10/2"|bc`%" 百分數:5.00%在shell下 $(( )) 就可以做運算
[root@VM-8-7-centos shell_01]# $(( 10+20)) -bash: 30: command not found [root@VM-8-7-centos shell_01]# echo $(( 10+50)) 60 [root@VM-8-7-centos shell_01]# echo $((10/3)) 3 [root@VM-8-7-centos shell_01]# echo $((10%3)) 1?
變量
在編程中,我們總有一些數據需要臨時存放在內存中,以待后續使用時快速讀出。內存在系統啟動的時候按照1B一個單位劃分為若干塊,然后統一編號(16進制編號),并對內存的使用情況做記錄,保存在內存跟蹤表中。
假如我將1B的字符存入內存中,如何讀取出來?就是通過變量的
變量:是編程中最常用的一種臨時在內存中存取數據的一種方式
就比如我們 0X3 這個位置是內存中的第三塊,計算機認識,可以我們不知道,那么我們就可以為這塊區域起一個邏輯名字,然后在往這塊區域中存值。到時候取值也可以使用0X3 這個物理地址 也可以使用我們定義的邏輯名字
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-h7MlVWYo-1631417107601)(E:\Java筆記\picture\image-20210827132419037.png)]
所以變量就是內存中一塊地址的一個邏輯名字。
當我們從腳本中定義變量存值,可以從以下方面看到變化:
內存占用:如果存的是一個字符則占用一個字節,如果存的是字符串這占用長度+1個字節。因為最后有一個'\0'代表結束標識
變量名與空間的對應關系:計算機會將對應的內存空間和變量名綁定在一起,此時代表這段空間已經被程序占用,其他程序不可用,然后將變量名對應的值存入對應的內存空間。
變量的分類
- 本地變量:用戶私有變量,只有本用戶可以使用,保存在家目錄下的.bash_profile 、 .bashrc 文件中。用戶登錄成功后才將命令加載進內存
- 全局變量:所有用戶都可以使用,保存在/etc/profile 、 /etc/bashrc 文件中。在用戶登錄之前就加載進內存中
- 用戶自定義變量: 用戶自定義,比如腳本中的變量。
建議變量的命名采用大寫 和命令區分。
#!/usr/bin/bash # Author: hu shang # Created Time: 2021-08-27 21:14 # Script Discription: test user custom variable# 這里定義幾個變量 NAME='Hu Shang' AGE=21 SCORE=100# 這里讀取 echo "name=$NAME , age=$AGE"定義變量
格式:變量名=值
注意:
- shell編程中變量名與等號之間不能有空格,
- 變量的命名參照java命名規范,不能將變量名定義為bash中的命令(保留關鍵字)
- 字符串要用單引號或雙引號 引起來。
- shell是區分大小寫的,建議將變量命名全改為大寫,這樣可以和命令區分開
讀取變量內容
可以通過 $ 來讀取變量中的內容 格式:$變量名
取消變量
unset 變量名
當我們定義了一個變量,然后不想使用了,可以將電腦關機 存在內存中的變量就沒了,也可以使用unset 命令來實現
[root@VM-8-7-centos shell_02]# NAME='胡 尚' [root@VM-8-7-centos shell_02]# echo $NAME 胡 尚 [root@VM-8-7-centos shell_02]# unset NAME [root@VM-8-7-centos shell_02]# echo $NAME[root@VM-8-7-centos shell_02]#使用這個命令可以取消用戶自定義變量和本地變量、全局變量。比如我現在定義一個全局變量:
在/etc/profile目錄下添加一個變量
# 首先在/etc/profile 文件下添加變量 vim /etc/profile# 第二個 添加變量 # 這樣定義的一個變量 即使是在/etc/profile 文件中定義的變量,但其實還是一個本地變量,其他用戶還是使用不了 NAME='胡 尚' # 需要加上export 關鍵字 export NAME='胡 尚'# 修改了這個文件 還需要使用source命令讓它生效 source /etc/profile定義永久變量
寫在命令行就是臨時變量,關機重啟就沒了 如果想定義永久變量就定義在上面提到的文件中
特殊變量
- $0 代表當前腳本的名字
- $1 $2 … 代表傳參
- $* 代表所有的參數,其間隔為IFS內定參數的第一個字元
- @與@ 與@與*相同 不同之處在于不參照IFS
- $# 參數的數量
- $ 執行上一條指令的返回值
- $$ 腳本執行進程號
- $_ 顯示出最后一個執行命令
數組
變量和數組的區別就是,變量一次只能存一個值,數組一次可以存多個值。
基本數組
可以讓用戶一次性賦予多個值,使用時通過索引來調用值
定義格式:數組名=(元素1 元素2 元素3 ...)
數組的讀取:${數組名[索引]} 索引從0開始
數組的賦值:
- 一次性賦值多個 數組名=(元素1 元素2 元素3 ...)
- 一次性賦值一個 數組名[索引]= 元素
訪問數組元素:
- echo ${數組名[0]} 訪問數組中第一個元素
- echo ${數組名[@]} 訪問數組中全部元素
- echo ${#數組名[0]} 統計數組元素個數
- echo ${數組名[@]:2} 從索引為2的位置開始打印數組中的所有元素
- echo ${數組名[@]:2:4} 從索引為2的位置開始打印 共打印4個元素
- echo ${!數組名[@]} 獲取數組元素的索引
輸出結果為:
[root@VM-8-7-centos shell_02]# bash array.sh 根據數據索引來獲取值: a 獲取全部值: a b c d e f 獲取數組長度: 6 從索引為2的位置開始打印: c d e f 從索引為2的位置開始打印,共打印3個 c d e 輸出數組的索引: 0 1 2 3 4 5索引也可以自定義,但是就需要使用到關聯數組了
關聯數組
關聯數組允許用戶自定義索引,這樣使用起來更方便 高效。在創建關聯數組時需要先聲明,如果不聲明那么創建的就是一個基本數組
#!/usr/bin/bash # Author: hu shang # Created Time: 2021-08-28 11:25 # Script Discription: associate array# 聲明一個關聯數組 declare -A ASS_ARRAY1 # 然后一次性賦一個值 ASS_ARRAY1[name]='hushang' ASS_ARRAY1[age]=21 echo ${ASS_ARRAY1[name]}# 聲明第二個關聯數組 一次性賦多個值 declare -A ASS_ARRAY2 ASS_ARRAY2=([name]='aaaaa' [age]=22) echo "第二個關聯數組的name屬性值是:${ASS_ARRAY2[name]}"五大運算
數學比較運算
這里比較是的整形。
- -eq 等于
- -gt 大于
- -lt 小于
- -ge 大于等于
- -le 小于等于
- ne 不等于
如果某種情況下需要進行小數比較,可以先轉換為整數 然后在比較,就比如1.5 和 2 進行比較,都*10 然后比較就可以了
[root@VM-8-7-centos shell_02]# echo "1.5*10"|bc 15.0# cut -d 數字 分割命令 以 . 進行分割 -f1 是表示取分割都的第一個 [root@VM-8-7-centos shell_02]# echo "1.5*10"|bc|cut -d '.' -f1 15[root@VM-8-7-centos shell_02]# test `echo "1.5*10"|bc|cut -d '.' -f1` -lt $((2*10));echo $? 0字符串比較運算
首先字符串別忘了用雙引號引起來,
- == 等于
- != 不等于
- -n 檢查字符串長度是否大于0
- -z 檢查字符串長度是否為0
文件比較與檢查
-d 檢查目錄是否存在 -e 檢查文件或目錄是否存在 -f 檢查文件是否存在 -r 檢查文件是否存在且可讀 -s 檢查文件是否存在且不為空 -w 檢查文件是否存在且可寫 -x 檢查文件是否存在且可執行 -O 檢查文件是否存在并且被當前用戶擁有 -G 檢查文件是否存在并且默認組為當前用戶組 -nt file1 -nt file2 檢查file1是否比file2新 -ot file1 -ot file2 檢查file1是否比file2舊 -ef file1 -ef file2 檢查file1是否與file2是同一個文件,判定依據的是i節點以上只列出部分命令選項,詳細的可以通過:man test獲得。邏輯運算
- && 邏輯與
- || 邏輯或
- ! 邏輯非
賦值運算
- = 賦值運算符, 盡量在shell中前后就不要加空格了。
循環與流程控制
if
語法一:單if語句
滿足條件后執行一些命令,這里的條件就是上面的五大運算 一般也就是 數字 字符串 文件 這三個的比較判斷
if [ condition ] # 兩個中括號中需要有空格 thencommands fi寫一個腳本,當/tmp/abc這個目錄不存在時就創建它
#!/usr/bin/bash # Author: hu shang # Created Time: 2021-08-28 16:14 # Script Description: 測試if 如果/tmp/abc 這個目錄不存在就創建一個if [ ! -d /tmp/abc ]thenmkdir -v /tmp/abcecho "create /tmp/abc success" fiif-then-else語句
滿足條件后執行一些命令,如果不滿足就執行另一些
if [ condition ] # 兩個中括號中需要有空格 thencommands1elsecommands2 fi還是上面創建目錄的案例
#!/usr/bin/bash # Author: hu shang # Created Time: 2021-08-28 16:14 # Script Description: 測試if 如果/tmp/abc 這個目錄不存在就創建一個 如果存在就提示if [ ! -d /tmp/abc ]thenmkdir -v /tmp/abcecho "create /tmp/abc success" elseecho "creat /tmp/abc fail"echo "the dir already exist" fiif-then-elif語句
if [ conditon ]thencommands1elif [ condition ]thencommands2elif [ condition ]thencommands3…… elsecommandsN fi案例如下
#!/usr/bin/bash # Author: hu shang # Created Time: 2021-08-28 16:51 # Script Description: 測試 if then elif 語句 輸入兩個數 然后比較大小if [ $1 -eq $2 ]thenecho "$1 == $2" elif [ $1 -gt $2 ]thenecho "$1 > $2" elseecho "$1 < $2" fi這里在執行這個腳本時,還可以在后面加上兩個值 表示腳本中的$1 與 $2 兩個變量
[root@VM-8-7-centos shell_02]# bash test_if_compare.sh 1 1 1 == 1 [root@VM-8-7-centos shell_02]# bash test_if_compare.sh 1 2 1 < 2 [root@VM-8-7-centos shell_02]# bash test_if_compare.sh 1 0 1 > 0其他用法
條件符號使用雙小圓括號,可以在條件中植入數學表達式。需要注意的就是 在雙小圓括號中 比較是使用的我們傳統的符號 而不是 -gt 這種
# if的另一用法 用兩個小括號 可以用來做整數的判斷 if (( 100+20 > 150 ));thenecho "yes" elseecho "no" fi使用雙方括號,可以在條件中使用通配符 可以做字符串匹配
# if 的另一種用法 使用兩個方括號 可以用通配符 # 使用循環 將 rx開頭的字符串打印出來 for TEMP_VAR in aaa abc dede rxaa rxbb rxccdoif [[ "$TEMP_VAR" == rx* ]];thenecho "$TEMP_VAR"fi done程序的判斷越多 越智能。
for循環
for語法一
for 變量名 in value1 value2 ...do命令段 done這個意思是,將in后面的值依次賦值給前面的臨時變量,然后執行一次命令段,再賦值下一個value,在執行一次
#!/usr/bin/bash # Author: hu shang # Created Time: 2021-08-28 18:09 # Script Description: for循環的練習 # 輸出 1 - 9 之間的數 for var in `seq 1 9`doecho "$var" doneseq 這個命令 就是一個數數的命令
[root@VM-8-7-centos shell_02]# seq 1 5 1 2 3 4 5 [root@VM-8-7-centos shell_02]# seq 5 -1 1 5 4 3 2 1語法二
for ((變量;條件;自增自減))do代碼段 done# 輸出1-9 的腳本如下 for ((i=1;i<10;i++))doecho "$i" done# 當有多個字段時,也和java沒什么區別 for ((i=1,j=9;i<10,j>0;i++,j--))doecho "$i --- $j" done循環控制語句
- sleep N 休眠N秒鐘
- continue 跳出本輪循環
- break 終止循環
break 后面還可以跟一個數字
for ((;;))doecho "aaa"for ((;;))doecho "bb"break 2 # 這里如果寫1 就表示跳過離break最近的這個內循環 如果寫2 這里就表示跳出外循環了done donewhile循環
如果明確知道了循環的次數就推薦使用for,如果不知道循環次數還是推薦使用while循環。
語法:
while [ condition ] do循環體 done# 可以在多個條件之間使用邏輯運算符 while [ condition ] && [ condition ]do循環體 donewhile還有一些嵌套使用,還是比較簡單,嵌套if while for
until循環
until循環和while循環語法上一樣,區別是,while是當條件為true時繼續循環,而until剛好相反,條件為false時才循環
until [ condition ] do循環體 donecase多分支語句
語法:
case 變量 in 條件1) 代碼段 ;; 條件2)代碼段 ;; ...... # 如果都不滿足 則執行默認的代碼段 *)代碼段 ;; esac# 每個代碼塊執行完使用;;結尾, case開始 esac倒過來寫表示改語句結束小案例
#!/usr/bin/bash # Author: hushang # Created Time: 2021-08-31 13:04 # Script Description: case多分支語句的練習 根據用戶輸入的值來輸出對應的字符串for ((;;)) doread -p "number: " Ncase $N in1)echo "aaaaa";;2)echo "bbbbb";;3)echo "ccccc";;4)break;;*)echo "輸入有誤,請輸入{1|2|3|4} 輸入4退出";;esac done # 如果當有多個條件中的任意一個滿足就執行某個case分支的代碼段的話 可以使用 case 變量 in 條件1|條件2) 代碼段 ;; *)代碼塊 ;; esacshell其他知識
shell函數
函數的優點就是代碼模塊化。函數也就是方法。
語法:
# 語法一 函數名 () {代碼塊return N }# 語法二 function 函數名 {代碼塊return N }上面的僅僅是定義函數,如果想調用的話 直接寫函數名。比如
start () {echo "start ....... [ok]" }# 啟動函數 start/etc/init.d/functions 目錄下有很多的函數
正則表達式
它是文本模式匹配,作用就是用它提供的特殊字符生成一個公式,用這個公式從海量的數據中篩選出我需要的數據。
shell也支撐正則表達式,但并不是所有命令都支撐,常見的支撐的命令有:grep sed awk
特殊字符
| ^ | 錨定一個開頭字符 |
| & | 錨定一個結尾字符 |
如果兩個符號一起使用就是精確匹配,如果只是使用其中一個是模糊匹配。
# 假如現在有一個文件 file.txt 中存放了很多字符串 # 查詢以a字符串開頭 grep命令默認是不支持正則表達式的,需要加上-e屬性才能支撐 [root@VM-8-7-centos shell_02]# grep -e "^a" file.txt# grep -e 等于 egrep # 查詢以c結尾的字符串 [root@VM-8-7-centos shell_02]# egrep "c&" file.txt# 查詢以a開頭c結尾的字符串 下面的寫法是精確匹配 最后的結果只能查詢出來ac字符串 [root@VM-8-7-centos shell_02]# egrep "^ac&" file.txt| . | 匹配一個除回車外的任意字符 |
| () | 字符串分組 , 使用場景比如以a或b字符開頭 |
| [] | 定義字符串,匹配括號中的一個字符 |
| [^] | 正好和上面相反,表示除了括號中的字符不匹配,其他的字符都匹配 |
| \ | 轉義 |
| | | 或 |
| * | 某個字符之后加*表示改字符可以出現[o,+∞]次 |
| ? | 某個字符出現[0,1]次 |
| + | 某個字符出現[1,+∞]次 |
| {n,m} | 某個字符出現[n,m]次 |
| {m} | 正好出現m次 |
posix特殊字符
[:alnum:] 這個是一個字符串,使用是需要 [[]] ,最外面的方括號表示一個字符,里面的就是一個posix特殊字符。
對文件的操作
對文件進行增刪改的操作,使用vim的確也可以實現,但vim命令是交互式的,shell腳本不支持交互式去調用文件,這就需要使用到sed命令,它可以直接對文本進行操作而不需要交互
sed命令,是linux中提供的一個行編輯器命令,使用者只能在命令行輸入編輯命令、指定文件名,然后在屏幕上查看輸出,它和文本編輯器的區別是文本編輯器是針對文本,而行編輯器針對的是文件中的某一行,它一次處理文件中的某一行
如果一個文件幾百MB,直接用vim進行打開會讀取全都文件的內容,比較暫用文件內存,所以對于大文件可以使用行編輯器。
sed數據處理原理
首先讀取文件中的一行數據到內存中,然后在內存中進行處理,然后輸出到電腦屏幕。所以它默認不會修改源文件,修改的只是讀取到內存中的數據。如果想修改文件中的內容就需要加一個命令選項
語法:
sed [options] '{command}[flags]' [文件名] # 其中{} 是必填項各個位置能夠填寫的參數是
#options選項 -e script 將腳本中指定的命令添加到處理輸入時執行的命令中 多條件,一行中要有多個操作 -f script 將文件中指定的命令添加到處理輸入時執行的命令中 -n 抑制自動輸出 -i 編輯文件內容 -i.bak 修改時同時創建.bak備份文件。 -r 使用擴展的正則表達式 ! 取反 (跟在模式條件后與shell有所區別)#command 對文件干什么 sed常用內部命令 a 在匹配后面添加 i 在匹配前面添加 d 刪除 s 查找替換 字符串 c 更改 y 轉換 N D P p 打印#flags 數字 表示新文本替換的模式 g: 表示用新文本替換現有文本的全部實例 p: 表示打印原始的內容 w filename: 將替換的結果寫入文件首先創建一個文本文件,并輸入一些內容
[root@VM-8-7-centos shell_04]# vim data.txt1 the quick brown fox jumps over the lazy dog. 2 the quick brown fox jumps over the lazy dog. 3 the quick brown fox jumps over the lazy dog. 4 the quick brown fox jumps over the lazy dog. 5 the quick brown fox jumps over the lazy dog.開始set命令
# 在每一行后面添加hello字符串 [root@VM-8-7-centos shell_04]# sed 'ahello' data.txt 1 the quick brown fox jumps over the lazy dog. hello 2 the quick brown fox jumps over the lazy dog. hello 3 the quick brown fox jumps over the lazy dog. hello 4 the quick brown fox jumps over the lazy dog. hello 5 the quick brown fox jumps over the lazy dog. hello# 第一個字母就表示命令 為了好區分開可以在命令和要插入的數據之間加一個 \ [root@VM-8-7-centos shell_04]# sed 'a\hello' data.txt 1 the quick brown fox jumps over the lazy dog. hello 2 the quick brown fox jumps over the lazy dog. hello 3 the quick brown fox jumps over the lazy dog. hello 4 the quick brown fox jumps over the lazy dog. hello 5 the quick brown fox jumps over the lazy dog. hello# 還可以在指定的一行后面添加數據 比如在第三行添加數據 只是在命令前面加一行即可 [root@VM-8-7-centos shell_04]# sed '3a\hello' data.txt 1 the quick brown fox jumps over the lazy dog. 2 the quick brown fox jumps over the lazy dog. 3 the quick brown fox jumps over the lazy dog. hello 4 the quick brown fox jumps over the lazy dog. 5 the quick brown fox jumps over the lazy dog.# 還可以在一個范圍中添加數據 就比如在2-4行添加數據 [root@VM-8-7-centos shell_04]# sed '2,4a\hello' data.txt 1 the quick brown fox jumps over the lazy dog. 2 the quick brown fox jumps over the lazy dog. hello 3 the quick brown fox jumps over the lazy dog. hello 4 the quick brown fox jumps over the lazy dog. hello 5 the quick brown fox jumps over the lazy dog.# 上面的幾種都不太適用于生產的環境,因為到時候不可能一行一行的去數 # 有一種匹配模式 可以搜索 特定的一些行進行新增 sed '/特定字符串/命令\要新增的字符串' 文件名 [root@VM-8-7-centos shell_04]# sed '/3 the quick/a\hello' data.txt 1 the quick brown fox jumps over the lazy dog. 2 the quick brown fox jumps over the lazy dog. 3 the quick brown fox jumps over the lazy dog. hello 4 the quick brown fox jumps over the lazy dog. 5 the quick brown fox jumps over the lazy dog.# a 命令是在一行的后面進行追加,i是在一行的前面進行新增 [root@VM-8-7-centos shell_04]# sed 'i\hello' data.txt hello 1 the quick brown fox jumps over the lazy dog. hello 2 the quick brown fox jumps over the lazy dog. hello 3 the quick brown fox jumps over the lazy dog. hello 4 the quick brown fox jumps over the lazy dog. hello 5 the quick brown fox jumps over the lazy dog. # 還有其他幾個 [root@VM-8-7-centos shell_04]# sed '3i\hello' data.txt # 在第三行插入字符串 [root@VM-8-7-centos shell_04]# sed '2,4\hello' data.txt # 在第2-4行插入字符串 [root@VM-8-7-centos shell_04]# sed '/3 the qu/\hello' data.txt # 在這一個特定字符串的這一行插入字符串# 刪除第三行 [root@VM-8-7-centos shell_04]# sed '3d' data.txt 1 the quick brown fox jumps over the lazy dog. 2 the quick brown fox jumps over the lazy dog. 4 the quick brown fox jumps over the lazy dog. 5 the quick brown fox jumps over the lazy dog.sed命令默認不支持正則表達式,可以加一個-r的名稱選項,比如我想刪除一個文件中所有# 開頭的注釋以及 空行
[root@VM-8-7-centos shell_04]# sed -r '/(^#|#|^$)/d' /home/hs/shell/shell_03/while_circulation.sh fun1 () { read -p "username: " USER while [ $USER != "root" ]doecho "賬號錯誤"read -p "username: " USER done } while read idoecho "$i" done < $1#上面的這行 sed -r '/(^#|#|^$)/d' /home/hs/shell/shell_03/while_circulation.sh '
-r 是讓后面支持正則表達式
/ ... / 這個是開啟匹配模式
(^#|#|^$) 這個表示以#開頭 或者是包含# 或者空行
d 這個命令是表示刪除
最后的是文件名,所以上面一行代表的意思就是刪除腳本中的注釋與空行。
增加和刪除都已經出現了,接下來是修改 命令是 s 和 c
# 修改有兩種 替換與修改 首先是替換 將dog替換為cat [root@VM-8-7-centos shell_04]# cat data.txt 1 the quick brown fox jumps over the lazy dog. 2 the quick brown fox jumps over the lazy dog. 3 the quick brown fox jumps over the lazy dog. 4 the quick brown fox jumps over the lazy dog. 5 the quick brown fox jumps over the lazy dog. # 命令格式是 sed 's/原字符串/新字符串/' 文件名 [root@VM-8-7-centos shell_04]# sed 's/dog/cat/' data.txt 1 the quick brown fox jumps over the lazy cat. 2 the quick brown fox jumps over the lazy cat. 3 the quick brown fox jumps over the lazy cat. 4 the quick brown fox jumps over the lazy cat. 5 the quick brown fox jumps over the lazy cat. [root@VM-8-7-centos shell_04]# sed '3s/dog/cat/' data.txt 特定行 [root@VM-8-7-centos shell_04]# sed '2,4s/dog/cat/' data.txt 一個范圍的行數 [root@VM-8-7-centos shell_04]# sed '/3 the quick/s/dog/cat/' data.txt 匹配模式# 修改 命令為c 將每一行的內容修改為 [root@VM-8-7-centos shell_04]# sed 'c\hello world' data.txt hello world hello world hello world hello world hello world # 有一個小細節 如果是想修改2-4行 使用其他的方式 它就會把2-4行刪除 然后重新新增一行 [root@VM-8-7-centos shell_04]# sed '2,4c\hello world' data.txt 1 the quick brown fox jumps over the lazy dog. hello world 5 the quick brown fox jumps over the lazy dog.還有轉換,將一個字母轉換為另一個字母
[root@VM-8-7-centos shell_04]# cat data.txt 1 the quick brown fox jumps over the lazy dog. 2 the quick brown fox jumps over the lazy dog. 3 the quick brown fox jumps over the lazy dog. 4 the quick brown fox jumps over the lazy dog. 5 the quick brown fox jumps over the lazy dog. # 將a轉換為A b轉換為B 這里注意 位置是一一對應的 中間字符串第一個只會轉換為后面的字符串的第一個 [root@VM-8-7-centos shell_04]# sed 'y/abcde/ABCDE/' data.txt 1 thE quiCk Brown fox jumps ovEr thE lAzy Dog. 2 thE quiCk Brown fox jumps ovEr thE lAzy Dog. 3 thE quiCk Brown fox jumps ovEr thE lAzy Dog. 4 thE quiCk Brown fox jumps ovEr thE lAzy Dog. 5 thE quiCk Brown fox jumps ovEr thE lAzy Dog.將文件的內容打印到屏幕
[root@VM-8-7-centos shell_04]# sed 'p' data.txt 1 the quick brown fox jumps over the lazy dog. 1 the quick brown fox jumps over the lazy dog. 2 the quick brown fox jumps over the lazy dog. 2 the quick brown fox jumps over the lazy dog. 3 the quick brown fox jumps over the lazy dog. 3 the quick brown fox jumps over the lazy dog. 4 the quick brown fox jumps over the lazy dog. 4 the quick brown fox jumps over the lazy dog. 5 the quick brown fox jumps over the lazy dog. 5 the quick brown fox jumps over the lazy dog.這里會出現重復的,因為這里將文件的內容打印到屏幕 還會將內存的數據打印到屏幕。
對文件的補充
sed命令格式:sed [命令選項] '{命令}[flag標志]' [文件名]
各個位置能夠填寫的參數是
#options選項 -e script 將腳本中指定的命令添加到處理輸入時執行的命令中 多條件,一行中要有多個操作 -f script 將文件中指定的命令添加到處理輸入時執行的命令中 -n 抑制自動輸出 -i 編輯文件內容 -i.bak 修改時同時創建.bak備份文件。 -r 使用擴展的正則表達式 ! 取反 (跟在模式條件后與shell有所區別)#command 對文件干什么 sed常用內部命令 a 在匹配后面添加 i 在匹配前面添加 d 刪除 s 查找替換 字符串 c 更改 y 轉換 N D P p 打印#flags 數字 表示新文本替換的模式 g: 表示用新文本替換現有文本的全部實例 p: 表示打印原始的內容 w filename: 將替換的結果寫入文件上面主要是將了命令相關的知識 還講了命令選項-r 讓后面支持正則表達式 接下來主要是將flag標志 這其實就是對命令的一個補充 還有一些其他的命令選項。
假如我現在將data.txt文件的內容改一下 結尾再加一個dog
1 the quick brown fox jumps over the lazy dog.dog 2 the quick brown fox jumps over the lazy dog.dog 3 the quick brown fox jumps over the lazy dog.dog 4 the quick brown fox jumps over the lazy dog.dog 5 the quick brown fox jumps over the lazy dog.dog接下來對這個文件進行操作
現在繼續將dog單詞替換為cat
[root@VM-8-7-centos shell_04]# sed 's/dog/cat/' data.txt 1 the quick brown fox jumps over the lazy cat.dog 2 the quick brown fox jumps over the lazy cat.dog 3 the quick brown fox jumps over the lazy cat.dog 4 the quick brown fox jumps over the lazy cat.dog 5 the quick brown fox jumps over the lazy cat.dog這就會出現僅僅只是替換了第一個dog單詞改為了cat。如果我想將讀取到內充中的這一行中所有的dog都替換為cat如何實現?如果我僅僅替換第二次出現的dog又如何實現?這就需要使用到flag標志了。
# 直接在標志位寫一個數字2即可實現將第二個dog替換為cat [root@VM-8-7-centos shell_04]# sed 's/dog/cat/2' data.txt 1 the quick brown fox jumps over the lazy dog.cat 2 the quick brown fox jumps over the lazy dog.cat 3 the quick brown fox jumps over the lazy dog.cat 4 the quick brown fox jumps over the lazy dog.cat 5 the quick brown fox jumps over the lazy dog.cat# 如果在標志位使用g 這是將一行中所有的dog替換為cat [root@VM-8-7-centos shell_04]# sed 's/dog/cat/g' data.txt 1 the quick brown fox jumps over the lazy cat.cat 2 the quick brown fox jumps over the lazy cat.cat 3 the quick brown fox jumps over the lazy cat.cat 4 the quick brown fox jumps over the lazy cat.cat 5 the quick brown fox jumps over the lazy cat.cat還可以打印輸出 比如打印輸出第三行
[root@VM-8-7-centos shell_04]# sed '3s/dog/cat/p' data.txt 1 the quick brown fox jumps over the lazy dog.dog 2 the quick brown fox jumps over the lazy dog.dog 3 the quick brown fox jumps over the lazy cat.dog 3 the quick brown fox jumps over the lazy cat.dog 4 the quick brown fox jumps over the lazy dog.dog 5 the quick brown fox jumps over the lazy dog.dog現在所有的修改都是針對內存來進行操作的,修改數據后真正的文件內容不會改變 如果想修改的內容讓文件改變就在標志位寫上 w
# 標志位 后面還需要寫一個文件名 表示將修改后的內容保存至哪一個文件 [root@VM-8-7-centos shell_04]# sed 's/dog/cat/w data_copy.txt' data.txt 1 the quick brown fox jumps over the lazy cat.dog 2 the quick brown fox jumps over the lazy cat.dog 3 the quick brown fox jumps over the lazy cat.dog 4 the quick brown fox jumps over the lazy cat.dog 5 the quick brown fox jumps over the lazy cat.dog [root@VM-8-7-centos shell_04]# ls data_copy.txt data.txt [root@VM-8-7-centos shell_04]# cat data_copy.txt 1 the quick brown fox jumps over the lazy cat.dog 2 the quick brown fox jumps over the lazy cat.dog 3 the quick brown fox jumps over the lazy cat.dog 4 the quick brown fox jumps over the lazy cat.dog 5 the quick brown fox jumps over the lazy cat.dog# 如果不寫文件名是會報錯的 [root@VM-8-7-centos shell_04]# sed 's/dog/cat/w' data.txt sed: couldn't open file : No such file or directory上面是修改了第一個dog單詞,如果我想修改一行中所有的dog單詞 然后將修改的結果進行保存至另一個文件中,問題就是標志位的命令可不可使用多個,答案是可以的
[root@VM-8-7-centos shell_04]# sed 's/dog/cat/gw aa.txt' data.txt 1 the quick brown fox jumps over the lazy cat.cat 2 the quick brown fox jumps over the lazy cat.cat 3 the quick brown fox jumps over the lazy cat.cat 4 the quick brown fox jumps over the lazy cat.cat 5 the quick brown fox jumps over the lazy cat.cat [root@VM-8-7-centos shell_04]# ls aa.txt data.txt [root@VM-8-7-centos shell_04]# cat aa.txt 1 the quick brown fox jumps over the lazy cat.cat 2 the quick brown fox jumps over the lazy cat.cat 3 the quick brown fox jumps over the lazy cat.cat 4 the quick brown fox jumps over the lazy cat.cat 5 the quick brown fox jumps over the lazy cat.cat我想能不能修改后的內容保存在原來的文件中,試了一下,結果導致原文件中的內容都沒有了
[root@VM-8-7-centos shell_04]# sed 's/dog/cat/w data.txt' data.txt接下來是講命令選項 ,命令選項是對sed命令的補充
首先是僅僅打印我修改了的數據,內存中讀入的數據不打印 使用-n
[root@VM-8-7-centos shell_04]# sed -n '3s/dog/cat/p' data.txt 3 the quick brown fox jumps over the lazy cat.dog [root@VM-8-7-centos shell_04]# sed -n '3s/dog/cat/' data.txt [root@VM-8-7-centos shell_04]# # 加上-n就可以僅僅顯示我們要打印的數據,如果沒有在命令或者flag標志中選擇p打印的話 -n最后是沒有任何數據顯示的還可以執行多個命令,就比如我要將brown單詞改為green dog單詞改為cat 像這種需要執行多個命令的就需要使用 -e 中間用; 隔開
[root@VM-8-7-centos shell_04]# sed -e 's/brown/green/;s/dog/cat/g' data.txt 1 the quick green fox jumps over the lazy cat.cat 2 the quick green fox jumps over the lazy cat.cat 3 the quick green fox jumps over the lazy cat.cat 4 the quick green fox jumps over the lazy cat.cat 5 the quick green fox jumps over the lazy cat.cat還可以將命令寫入到文件中,執行時直接讀取文件中的命令來執行 需要使用-f
# 首先創建一個文件 [root@VM-8-7-centos shell_04]# vim command.txt# 文件內容如下 還是上面的將brown單詞改為green dog單詞改為cat 因為這里命令沒有寫在一行 所以中間就不用分號隔開 s/brown/grent/ s/dog/cat/g# 然后在執行 command.txt為命令文件 data.txt為原數據文件 [root@VM-8-7-centos shell_04]# sed -f command.txt data.txt 1 the quick grent fox jumps over the lazy cat.cat 2 the quick grent fox jumps over the lazy cat.cat 3 the quick grent fox jumps over the lazy cat.cat 4 the quick grent fox jumps over the lazy cat.cat 5 the quick grent fox jumps over the lazy cat.cat修改源文件,上面使用命令flag標志w 只是將打印內容寫入到另一個文件,現在是對源文件進行修改。
[root@VM-8-7-centos shell_04]# cat data.txt 1 the quick brown fox jumps over the lazy dog.dog 2 the quick brown fox jumps over the lazy dog.dog 3 the quick brown fox jumps over the lazy dog.dog 4 the quick brown fox jumps over the lazy dog.dog 5 the quick brown fox jumps over the lazy dog.dog [root@VM-8-7-centos shell_04]# sed -i 's/dog/cat/g' data.txt # 將所有的dog修改為cat 后屏幕是沒有輸出 但是再查看原文件內容已經發生了改變 [root@VM-8-7-centos shell_04]# cat data.txt 1 the quick brown fox jumps over the lazy cat.cat 2 the quick brown fox jumps over the lazy cat.cat 3 the quick brown fox jumps over the lazy cat.cat 4 the quick brown fox jumps over the lazy cat.cat 5 the quick brown fox jumps over the lazy cat.cat# 在日常中 修改源文件其實是很危險的操作 因為這是不可逆的 可以使用-i.xxx 先對原文件進行備份,然后再對原文件進行修改 # 現在的data.txt文件內容 [root@VM-8-7-centos shell_04]# cat data.txt 1 the quick brown fox jumps over the lazy cat.cat 2 the quick brown fox jumps over the lazy cat.cat 3 the quick brown fox jumps over the lazy cat.cat 4 the quick brown fox jumps over the lazy cat.cat 5 the quick brown fox jumps over the lazy cat.cat # 現在進行修改操作 [root@VM-8-7-centos shell_04]# sed -i.0905 's/cat/dog/g' data.txt # 這個時候就會自動創建一個data.txt.0905文件 [root@VM-8-7-centos shell_04]# ls command.txt data.txt data.txt.0905 # 修改后的data.txt文件 [root@VM-8-7-centos shell_04]# cat data.txt 1 the quick brown fox jumps over the lazy dog.dog 2 the quick brown fox jumps over the lazy dog.dog 3 the quick brown fox jumps over the lazy dog.dog 4 the quick brown fox jumps over the lazy dog.dog 5 the quick brown fox jumps over the lazy dog.dog # 修改前進行備份的原文件 [root@VM-8-7-centos shell_04]# cat data.txt.0905 1 the quick brown fox jumps over the lazy cat.cat 2 the quick brown fox jumps over the lazy cat.cat 3 the quick brown fox jumps over the lazy cat.cat 4 the quick brown fox jumps over the lazy cat.cat 5 the quick brown fox jumps over the lazy cat.catsed命令小技巧
統計data.txt文件有多少行
[root@VM-8-7-centos shell_04]# sed -n '$=' data.txt 5對輸出流處理
awk命令可以幫助我們從輸出流中把我們想要的數據找出來并對這些數據進行處理,awk也是一個行編輯器命令,可以截取某一行中某一列的內容并對這些內容進行處理、運算、輸出。
awk工作方式是讀取數據,將每一行數據視為一條記錄, 每條記錄以分隔符分為若干個字段 行的分隔符為回車 字段的分割為一個或多個空格
就比如求內存的使用率,所有的內存數以及已使用的內存都在一行的中,如果需要將我們想要的數據檢索出來并進行處理就可以使用awk命令
[root@VM-8-7-centos ~]# freetotal used free shared buff/cache available Mem: 1882008 458880 94056 592 1329072 1226400 Swap: 0 0 0語法:
awk [option命令選項] '[BEGIN]{program}[END]' [fileName]
命令選項為:
- -F fs 一行中各個字段的列分隔符 默認是空格 如果是其他的就需要使用該命令選項來指定分隔符
- -f file 指定讀取程序的文件名
- -v var=value awk使用的變量與值
awk的命令program必須放在兩個大括號中,并且必須用單引號將大括號引起來
awk的運行優先級:
- BEGIN: 在開始處理數據流之前執行,可選項
- program: 如何處理數據流,必選項
- END: 處理完數據流后執行,可選項
awk命令基本用法
awk的基本用法就是數據的提取功能,能夠從一行中提取某一個字段
首先創建一個文本文件
[root@VM-8-7-centos shell_04]# vim awk_data.txt1 the quick brown fox jumps over the lazy cat . dog 2 the quick brown fox jumps over the lazy cat . dog 3 the quick brown fox jumps over the lazy cat . dog 4 the quick brown fox jumps over the lazy cat . dog 5 the quick brown fox jumps over the lazy cat . dogawk命令對列的提取
字段相關內置變量
$0 表示整行文本
$1 表示文本行中的第一個數據字段
$2 表示文本行中的第二個數據字段
$N 表示文本行中的第N個數據字段
$NF 表示文本行中的最后一個數據字段
# 提取整行內容 awk的打印輸出命令是print [root@VM-8-7-centos shell_04]# awk '{print $0}' awk_data.txt 1 the quick brown fox jumps over the lazy cat . dog 2 the quick brown fox jumps over the lazy cat . dog 3 the quick brown fox jumps over the lazy cat . dog 4 the quick brown fox jumps over the lazy cat . dog 5 the quick brown fox jumps over the lazy cat . dog# 提取每行第三個字段的內容 [root@VM-8-7-centos shell_04]# awk '{print $3}' awk_data.txt quick quick quick quick quick# 還可以打印多個字段 直接在{} 中寫多個$ 即可 中間用逗號分割 [root@VM-8-7-centos shell_04]# awk '{print $1,$3,$5}' awk_data.txt 1 quick fox 2 quick fox 3 quick fox 4 quick fox 5 quick fox對行的提取
上面會了對列的提取,如果我想提取某一行 可以使用NR來指定,或者開啟匹配模式
# 比如 提取第三行的整行內容 [root@VM-8-7-centos shell_04]# awk 'NR==3{print $0}' awk_data.txt 3 the quick brown fox jumps over the lazy cat . dog[root@VM-8-7-centos shell_04]# awk '/2 the/{print $0}' awk_data.txt 2 the quick brown fox jumps over the lazy cat . dog如果列的分隔符不是空格的情形下
上面都是對awk_data.txt文件進行操作,這是一個標準的文件,字段與字段之間采用的是空格分割的,那如果采用的其他符號進行分隔符就需要在option命令選項使用-F
# 比如這個文件,字段與字段之間采用的冒號分割 [root@VM-8-7-centos shell_04]# cat /etc/passwd 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 ......# 使用-F 指定字段分隔符 [root@VM-8-7-centos shell_04]# awk -F ":" '{print $1}' /etc/passwd root bin daemon adm lp sync shutdown halt ......# 還可以將 awk -F ":" 寫成 awk -F:改變輸出后的字段分割符
打印的多個字段默認采用的是空格分割,還可以改變, 格式為:awk '{print $1 "雙引號中寫自定義的分隔符" $2}' 文件名
# 默認輸出在屏幕后的字段是采用的空格分割 [root@VM-8-7-centos shell_04]# awk '{print $1,$3,$5}' awk_data.txt 1 quick fox 2 quick fox 3 quick fox 4 quick fox 5 quick fox# 改變分隔符后的輸出 [root@VM-8-7-centos shell_04]# awk '{print $1 "--" $3 "--" $5}' awk_data.txt 1--quick--fox 2--quick--fox 3--quick--fox 4--quick--fox 5--quick--fox其實就是打印字符串,雙引號引起來的就是字符串,如果沒有引起來的就是變量
awk的三個優先級
BEGIN的優先級最高 最先執行 它是在從輸出流中讀取數據之前進行的操作 , 它不依賴于輸出流 所以僅僅使用BEGIN允許最后沒有文件名
END 的優先級最低 最后執行 它是在輸出流中操作數據之后執行
[root@VM-8-7-centos shell_04]# awk 'BEGIN{print "begin...."}{print $0}END{print "end..."}' awk_data.txt begin.... 1 the quick brown fox jumps over the lazy cat . dog 2 the quick brown fox jumps over the lazy cat . dog 3 the quick brown fox jumps over the lazy cat . dog 4 the quick brown fox jumps over the lazy cat . dog 5 the quick brown fox jumps over the lazy cat . dog end...# 不需要數據源也可以輸出 [root@VM-8-7-centos shell_04]# awk 'BEGIN{print "begin...."}' begin....# 沒有提供數據源 所以無法輸出 [root@VM-8-7-centos shell_04]# awk '{print "test...."}'awk命令高級用法
awk是一門語言,可以定義變量,還可以定義數組,還可以進行運算,環境變量,流程控制。
定義變量,案例使用查看內存的使用率,如下:
# 第一個是總內存 第二個是剩余內存 [root@VM-8-7-centos shell_04]# head -2 /proc/meminfo MemTotal: 1882008 kB MemFree: 123520 kB[root@VM-8-7-centos shell_04]# head -2 /proc/meminfo | awk 'NR==1{t=$2}NR==2{f=$2;print (t-f)/t*100 "%"}' 93.4561%# 定義變量還可以這樣使用 [root@VM-8-7-centos shell_04]# awk 'BEGIN{name="胡尚";print name}' 胡尚定義數組
[root@VM-8-7-centos shell_04]# awk 'BEGIN{array[1]="hushang";array[2]="21";print array[1],array[2]}' hushang 21awk運算
- 賦值運算 =
- 比較運算 > >= == != <= <
- 數學運算 + - * / % ++ – **
- 邏輯運算 && || !
- 匹配運算 ~ !~ == !=
下面是匹配運算,也是用的比較多的
# passwd文件如下 [root@VM-8-7-centos shell_04]# cat /etc/passwd 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 ...# 使用 == 來進行精確匹配 只輸出第一個字段為root的一行 [root@VM-8-7-centos shell_04]# awk -F ":" '$1=="root"{print $0}' /etc/passwd root:x:0:0:root:/root:/bin/bash# 還可以使用模糊匹配 只要第一個字段中包含ro的都會被打印出來 [root@VM-8-7-centos shell_04]# awk '$1 ~ "ro"{print $0}' /etc/passwd root:x:0:0:root:/root:/bin/bash operator:x:11:0:operator:/root:/sbin/nologin chrony:x:997:995::/var/lib/chrony:/sbin/nologin環境變量
| FIELDWIDTHS | 以空格分隔的數字列表,用空格定義每個數據字段的精確寬度 |
| FS | 輸入字段分隔符號 數據源的字段分隔符 -F |
| OFS | 輸出字段分隔符號 |
| RS | 輸入記錄分隔符 |
| ORS | 輸出記錄分隔符號 |
awk流程控制與循環
if語句
# 首先是查看文件 [root@VM-8-7-centos shell_04]# cat awk_data.txt 1 the quick brown fox jumps over the lazy cat . dog 2 the quick brown fox jumps over the lazy cat . dog 3 the quick brown fox jumps over the lazy cat . dog 4 the quick brown fox jumps over the lazy cat . dog 5 the quick brown fox jumps over the lazy cat . dog# 打印第一個字段小于3的數據 [root@VM-8-7-centos shell_04]# awk '{if($0 < 3)print $0}' awk_data.txt 1 the quick brown fox jumps over the lazy cat . dog 2 the quick brown fox jumps over the lazy cat . dog # 上面是寫在一行中 還可以通過shift+enter 寫在多行 [root@VM-8-7-centos shell_04]# awk '{ > if($1<3) > print $0 > }' awk_data.txt 1 the quick brown fox jumps over the lazy cat . dog 2 the quick brown fox jumps over the lazy cat . dog# 但是不理解為什么下面 > 3 的條件竟然將第三行輸出了 [root@VM-8-7-centos shell_04]# awk '{if($0 > 3)print $0}' awk_data.txt 3 the quick brown fox jumps over the lazy cat . dog 4 the quick brown fox jumps over the lazy cat . dog 5 the quick brown fox jumps over the lazy cat . dog [root@VM-8-7-centos shell_04]# awk '{if($0 >= 3)print $0}' awk_data.txt 3 the quick brown fox jumps over the lazy cat . dog 4 the quick brown fox jumps over the lazy cat . dog 5 the quick brown fox jumps over the lazy cat . dogif…else…語句
[root@VM-8-7-centos shell_04]# awk '{ > if($1<3) > print $1*2 > else > print $1/2 > '} awk_data.txt 2 4 1.5 2 2.5for循環
首先創建一個文件,保存幾個數字
[root@VM-8-7-centos shell_04]# vim number.txt60 50 100 150 30 10 70 100 40求和
# 首先使用-v命令選項定義一個變量 然后進行循環 最后使用end進行輸出 [root@VM-8-7-centos shell_04]# awk -v "sum=0" '{for(i=1;i<4;i++){sum+=$i}}END{print sum}' number.txt 610# 在begin中定義變量也可以 [root@VM-8-7-centos shell_04]# awk 'BEGIN{sum=0}{for(i=1;i<4;i++){sum+=$i}}END{print sum}' number.txt 610# 使用多行的格式 [root@VM-8-7-centos shell_04]# awk -v "sum=0" '{ > for(i=1;i<4;i++){ > sum+=$i > }}END{print sum}' number.txt 610while循環
使用while循環 輸出每行的幾個字段的和
[root@VM-8-7-centos shell_04]# cat number.txt 60 50 100 150 30 10 70 100 40[root@VM-8-7-centos shell_04]# awk '{ > i=1 > sum=0 > while(i<4){ > sum+=$i > i++ > } > print sum}' number.txt 210 190 210還有一個do…while格式。先執行循環在進行判斷
[root@VM-8-7-centos shell_04]# awk '{ > sum=0 > i=1 > do{ > sum+=$i > i++ > }while(i<4) > print sum}' number.txt 210 190 210循環控制語句
break
awk小技巧
# 打印行數 [root@VM-8-7-centos shell_04]# awk 'END{print NR}' number.txt 3# 打印最后一行內容 [root@VM-8-7-centos shell_04]# awk 'END{print $0}' number.txt 70 100 40# 打印列數 [root@VM-8-7-centos shell_04]# awk 'END{print NF}' number.txt 3腳本案例
監控一個主機的存活狀態
監控方法采用ping 使用的是icmp協議。如果能ping通則表示主機存活 如果ping不通則主機死亡
關于該知識點的一些問題
關于禁ping 防止DDOS攻擊
這里主機如果是禁ping 禁的是陌生人 。 禁止所有但是允許你自己的ip進行ping的操作
網絡有延遲,可能因為網絡的原因產生假報警問題,
需要設置ping的報警閥值,假如三次全部失敗就報警 主機down
ping的頻率
1-5秒ping一次都可以 但是不要毫秒級單位去ping
監控端口存活狀態
比較常見的監控方法是:
- 通過systemctl 或 service 命令來查看服務啟動狀態
- 通過lsof命令 查看端口是否存在
- 通過ps命令 查看進程
上面這三種都有可能出現 服務down了上述的一些東西還在 或者是 壓力過大 服務無法響應
這里推薦使用 telnet命令測試端口是否有響應
如果沒有該命令 那就安裝一下
# 安裝命令 yum -y install telnet# 測試一下連接當前服務器的22號端口 [root@VM-8-7-centos shell_05]# telnet 82.156.9.191 22 Trying 82.156.9.191... Connected to 82.156.9.191. Escape character is '^]'. SSH-2.0-OpenSSH_7.4 # 然后輸入quit退出 # 如果能夠出現 '^]' 符號就表示該端口是開放的 如果端口沒有開放就會提示connection # 這里有個小問題 如果我測試一個沒有開放的端口 就會一直等待 不會有提示信息輸出 可是視頻教程有一個連接超時的提示# 該命令的位置 [root@VM-8-7-centos shell_05]# which telnet /usr/bin/telnet補充知識點——創建臨時文件
mktemp 文件名.XXXXXX # 可以有多個X 但至少要有三個# 現有的文件 [root@VM-8-7-centos shell_05]# ls host_status.sh port_status.sh # 創建一個臨時文件 [root@VM-8-7-centos shell_05]# mktemp test.XXX test.uL5 # 創建后就會看到多了一個文件 [root@VM-8-7-centos shell_05]# ls host_status.sh port_status.sh test.uL5 # 再創建一次 [root@VM-8-7-centos shell_05]# mktemp test.XXXXXXX test.pikvvR9 [root@VM-8-7-centos shell_05]# ls host_status.sh port_status.sh test.pikvvR9 test.uL5 # 后面寫幾個X 就會隨機生成幾位# 還可以創建臨時文件夾, 使用-d命令選項 mktemp -d test.XXXXXXX腳本如下:
#!/usr/bin/bash # Author: hushang # Created Time: 2021-09-08 12:45 # Script Description: 監控一個主機的端口port_status () {# 首先判斷一下/usr/bin/telnet這個可執行文件是否存在 if [ ! -f /usr/bin/telnet ];thenecho "not fount command : telnet"exit 1 fi# 創建一個臨時文件 用來保存執行telnet命令后的輸出內容 TEMP_FILE=`mktemp port_status.XXXXX`# 開始測試端口是否存在 $1代表IP地址 $2代表端口 # 然后將執telnet命令 輸出在屏幕的結果保存在上面創建的一個臨時文件 (telnet $1 $2 <<EOF quit EOF ) &> $TEMP_FILE# 使用grep -e 通過檢索這個臨時文件 是否包含 ^] 字符 # &>/dev/null 這個是不需要將檢索臨時文件的結果輸出在屏幕上 if egrep "\^]" $TEMP_FILE &>/dev/null;thenecho "$1 $2 is open" elseecho "$1 $2 is close" fi# 將臨時文件刪除掉 rm -f $TEMP_FILE}# 上面寫的是一個函數,現在調用執行那個函數,將兩個參數傳給該方法 port_status $1 $2監控內存使用率
首先是查看內存使用情況
# total總共內存 used已使用 free剩余 shered共享內存 buff緩沖 [root@VM-8-7-centos ~]# free -mtotal used free shared buff/cache available Mem: 1837 448 122 0 1267 1197 Swap: 0 0 0# 第二個命令就是: [root@VM-8-7-centos shell_05]# cat /proc/meminfo MemTotal: 1882008 kB MemFree: 126520 kB MemAvailable: 1229092 kB Buffers: 125948 kB Cached: 1048056 kB SwapCached: 0 kB .....在這個里面 內存使用的優先級是 free —> cache —> buffer ----> Swap
當used的值不高 free的值不高 buff的值高 這種情況并不是內存緊張 ,只是很多東西讀入到內存中 沒有清空緩存而已,沒有釋放到free
當used的值高 free的值不高 buff的值也不高 這種情況才是內存緊張了
上面兩種命令隨便選擇一種使用都可以,這里采用第二種
# 統計已使用的內存占總內存的百分比 [root@VM-8-7-centos shell_05]# head -2 /proc/meminfo MemTotal: 1882008 kB MemFree: 126280 kB [root@VM-8-7-centos shell_05]# head -2 /proc/meminfo | awk 'NR==1{t=$2}NR==2{f=$2;print (t-f)/t*100"%"}' 93.3059%# 統計cache的使用率 [root@VM-8-7-centos shell_05]# head -5 /proc/meminfo MemTotal: 1882008 kB MemFree: 126036 kB MemAvailable: 1229168 kB Buffers: 126052 kB Cached: 1048504 kB [root@VM-8-7-centos shell_05]# head -5 /proc/meminfo | awk 'NR==1{t=$2}NR==5{c=$2;print c/t*100"%"}' 55.7171%# 統計buffer的使用率 [root@VM-8-7-centos shell_05]# head -5 /proc/meminfo | awk 'NR==1{t=$2}NR==4{b=$2;print b/t*100"%"}' 6.69902%腳本如下:
#!/usr/bin/bash # Author: hushang # Created Time: 2021-09-09 13:04 # Script Description: 監控內存的使用率memory_use(){memory_used=`head -2 /proc/meminfo | awk 'NR==1{t=$2}NR==2{f=$2;print (t-f)/t*100"%"}'`memory_cache=`head -5 /proc/meminfo | awk 'NR==1{t=$2}NR==5{c=$2;print c/t*100"%"}'`memory_buff=`head -5 /proc/meminfo | awk 'NR==1{t=$2}NR==4{b=$2;print b/t*100"%"}'`echo "memory used: $memory_used"echo "memory cache used: $memory_cache"echo "memory buff used: $memory_buff" } memory_use使用cpu或內存前十的進程
目的:通過監控找出一些非法占用內存高的進程,發現后停止該進程
監控方法:
ps 或 top 命令 這兩個命令的區別是ps的靜態的命令 顯示上一秒的進程情況,而 top 命令是動態的,顯示的數值會動態的改變。
通過對任務管理器中的進程對內存或cpu的使用情況進行整合、排序
使用上面兩個命令 其實顯示的內容都差不多
[root@VM-8-7-centos shell_05]# ps -aux USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND root 1 0.0 0.1 43612 3672 ? Ss Jun25 10:38 /usr/lib/systemd/systemd --system --deserialize 20 root 2 0.0 0.0 0 0 ? S Jun25 0:00 [kthreadd] root 4 0.0 0.0 0 0 ? S< Jun25 0:00 [kworker/0:0H] root 6 0.0 0.0 0 0 ? S Jun25 3:32 [ksoftirqd/0] root 7 0.0 0.0 0 0 ? S Jun25 0:00 [migration/0] root 8 0.0 0.0 0 0 ? S Jun25 0:00 [rcu_bh] ......# 需要用到的也就是RSS 這表示那個進程使用了多少物理內存# -n1 表示就打印一次 RES的值也就表示進程使用了多少物理內存 [root@VM-8-7-centos shell_05]# top -n1 top - 20:24:15 up 76 days, 10:03, 1 user, load average: 0.90, 0.82, 0.63 Tasks: 107 total, 2 running, 105 sleeping, 0 stopped, 0 zombie %Cpu(s): 0.0 us, 0.0 sy, 0.0 ni,100.0 id, 0.0 wa, 0.0 hi, 0.0 si, 0.0 st KiB Mem : 1882008 total, 181044 free, 458872 used, 1242092 buff/cache KiB Swap: 0 total, 0 free, 0 used. 1226416 avail Mem PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND 1047 root 20 0 50088 916 584 R 6.7 0.0 1321:32 rshim 1 root 20 0 43612 3672 2212 S 0.0 0.2 10:39.09 systemd 2 root 20 0 0 0 0 S 0.0 0.0 0:00.31 kthreadd 4 root 0 -20 0 0 0 S 0.0 0.0 0:00.00 kworker/0:0H 6 root 20 0 0 0 0 S 0.0 0.0 3:32.11 ksoftirqd/0 7 root rt 0 0 0 0 S 0.0 0.0 0:00.00 migration/0 # 將top命令打印在屏幕的內容輸入至一個臨時文件中 [root@VM-8-7-centos shell_05]# top -n1 > temp.txt # 查看該文件 內容如下 [root@VM-8-7-centos shell_05]# cat temp.txt top - 20:37:39 up 76 days, 10:16, 1 user, load average: 0.55, 0.44, 0.52 Tasks: 105 total, 2 running, 103 sleeping, 0 stopped, 0 zombie %Cpu(s): 0.0 us, 0.0 sy, 0.0 ni,100.0 id, 0.0 wa, 0.0 hi, 0.0 si, 0.0 st KiB Mem : 1882008 total, 180920 free, 457248 used, 1243840 buff/cache KiB Swap: 0 total, 0 free, 0 used. 1227996 avail Mem PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND 11345 rabbitmq 20 0 1827504 84188 4716 S 6.2 4.5 227:39.43 beam.smp 1 root 20 0 43612 3672 2212 S 0.0 0.2 10:39.46 systemd 2 root 20 0 0 0 0 S 0.0 0.0 0:00.31 kthreadd 4 root 0 -20 0 0 0 S 0.0 0.0 0:00.00 kworker/0:0H6 root 20 0 0 0 0 S 0.0 0.0 3:32.19 ksoftirqd/0 7 root rt 0 0 0 0 S 0.0 0.0 0:00.00 migration/0 8 root 20 0 0 0 0 S 0.0 0.0 0:00.00 rcu_bh 9 root 20 0 0 0 0 S 0.0 0.0 10:01.43 rcu_sched 10 root 0 -20 0 0 0 S 0.0 0.0 0:00.00 lru-add-drain 11 root rt 0 0 0 0 S 0.0 0.0 0:14.90 watchdog/0 13 root 20 0 0 0 0 S 0.0 0.0 0:00.00 kdevtmpfs 14 root 0 -20 0 0 0 S 0.0 0.0 0:00.00 netns 15 root 20 0 0 0 0 S 0.0 0.0 0:01.22 khungtaskd 16 root 0 -20 0 0 0 S 0.0 0.0 0:00.02 writeback 17 root 0 -20 0 0 0 S 0.0 0.0 0:00.00 kintegrityd18 root 0 -20 0 0 0 S 0.0 0.0 0:00.00 bioset 19 root 0 -20 0 0 0 S 0.0 0.0 0:00.00 bioset 20 root 0 -20 0 0 0 S 0.0 0.0 0:00.00 bioset21 root 0 -20 0 0 0 S 0.0 0.0 0:00.00 kblockd 22 root 0 -20 0 0 0 S 0.0 0.0 0:00.00 md 23 root 0 -20 0 0 0 S 0.0 0.0 0:00.00 edac-poller 24 root 0 -20 0 0 0 S 0.0 0.0 0:00.00 watchdogd 30 root 20 0 0 0 0 S 0.0 0.0 0:02.99 kswapd0 31 root 25 5 0 0 0 S 0.0 0.0 0:00.00 ksmd 32 root 39 19 0 0 0 S 0.0 0.0 0:06.20 khugepaged 33 root 0 -20 0 0 0 S 0.0 0.0 0:00.00 crypto 41 root 0 -20 0 0 0 S 0.0 0.0 0:00.00 kthrotld 43 root 0 -20 0 0 0 S 0.0 0.0 0:00.00 kmpath_rdacd 44 root 0 -20 0 0 0 S 0.0 0.0 0:00.00 kaluad 45 root 0 -20 0 0 0 S 0.0 0.0 0:00.00 kpsmoused 46 root 0 -20 0 0 0 S 0.0 0.0 0:00.00 ipv6_addrconf 59 root 0 -20 0 0 0 S 0.0 0.0 0:00.00 deferwq 98 root 20 0 0 0 0 S 0.0 0.0 0:23.00 kauditd 193 root 0 -20 0 0 0 S 0.0 0.0 0:00.00 iscsi_eh 245 root 0 -20 0 0 0 S 0.0 0.0 0:00.00 ata_sff 251 root 20 0 0 0 0 S 0.0 0.0 0:00.00 scsi_eh_0 252 root 0 -20 0 0 0 S 0.0 0.0 0:00.00 scsi_tmf_0但是如果我要創建一個腳本 所需要使用的內容是從第8行開始 那我如何讓內容從第八行開始顯示嘞? 這里可以使用tail命令
# 查看最后4行 如果想從頭開始就將數字寫我 +n [root@VM-8-7-centos shell_05]# tail -n -5 temp.txt 193 root 0 -20 0 0 0 S 0.0 0.0 0:00.00 iscsi_eh 245 root 0 -20 0 0 0 S 0.0 0.0 0:00.00 ata_sff 251 root 20 0 0 0 0 S 0.0 0.0 0:00.00 scsi_eh_0 252 root 0 -20 0 0 0 S 0.0 0.0 0:00.00 scsi_tmf_0 # 改為+8就表示從第八行開始展示 [root@VM-8-7-centos shell_05]# tail -n +8 temp.txt 11345 rabbitmq 20 0 1827504 84188 4716 S 6.2 4.5 227:39.43 beam.smp 1 root 20 0 43612 3672 2212 S 0.0 0.2 10:39.46 systemd 2 root 20 0 0 0 0 S 0.0 0.0 0:00.31 kthreadd 4 root 0 -20 0 0 0 S 0.0 0.0 0:00.00 kworker/0:0H 6 root 20 0 0 0 0 S 0.0 0.0 3:32.19 ksoftirqd/0 7 root rt 0 0 0 0 S 0.0 0.0 0:00.00 migration/0 8 root 20 0 0 0 0 S 0.0 0.0 0:00.00 rcu_bh 9 root 20 0 0 0 0 S 0.0 0.0 10:01.43 rcu_sched 10 root 0 -20 0 0 0 S 0.0 0.0 0:00.00 lru-add-drain 11 root rt 0 0 0 0 S 0.0 0.0 0:14.90 watchdog/0 13 root 20 0 0 0 0 S 0.0 0.0 0:00.00 kdevtmpfs 14 root 0 -20 0 0 0 S 0.0 0.0 0:00.00 netns 15 root 20 0 0 0 0 S 0.0 0.0 0:01.22 khungtaskd 16 root 0 -20 0 0 0 S 0.0 0.0 0:00.02 writeback 17 root 0 -20 0 0 0 S 0.0 0.0 0:00.00 kintegrityd 18 root 0 -20 0 0 0 S 0.0 0.0 0:00.00 bioset19 root 0 -20 0 0 0 S 0.0 0.0 0:00.00 bioset20 root 0 -20 0 0 0 S 0.0 0.0 0:00.00 bioset # 然后就使用awk命令定義一個數組 數組的名字就使用最后一個字段 數組的值就使用第六列 RES的值 文件內容有點問題 所以顯示有點問題 [root@VM-8-7-centos shell_05]# tail -n +8 temp.txt | awk '{array[$13]=$6}END{for (i in array) print i,array[i]}'scsi_eh_0 0 kpsmoused 0 md 0 kintegrityd 0 systemd 43612 kauditd 0 kmpath_rdacd 0 migration/0 0 scsi_tmf_0 0 iscsi_eh 0 crypto 0 writeback 0 kthrotld 084188 khungtaskd 0 watchdog/0 0 rcu_sched 0 ksmd 0 edac-poller 0 kblockd 0 bioset 0 lru-add-drain 0 kaluad 0 kswapd0 0 watchdogd 0 netns 0 kthreadd 0 ata_sff 0 rcu_bh 0 deferwq 0 khugepaged 0 kdevtmpfs 0 kworker/0:0H 0 ipv6_addrconf 0 ksoftirqd/0 0# 將內容進行排序 sort -k排序命令 2表示按第二列排序 -n表示數字 -r表示降序 # 最后再顯示前面十行 [root@VM-8-7-centos shell_05]# tail -n +8 temp.txt | awk '{array[$13]=$6}END{for (i in array) print i,array[i]}' | sort -k 2 -n -r | head -1084188 systemd 43612 writeback 0 watchdogd 0 watchdog/0 0 scsi_tmf_0 0 scsi_eh_0 0 rcu_sched 0 rcu_bh 0 netns 0文件內容的一些列字段有問題,但方法是這樣的:
有個問題:現在 top命令并沒有將所有的進程都打印出來 需要加一個 -b 命令選項
[root@VM-8-7-centos shell_05]# top -b -n 1 > temp.txt # 這里最后一個列 將$13改為了 $NF [root@VM-8-7-centos shell_05]# tail -n +8 temp.txt | awk '{array[$NF]=$6}END{for (i in array) print i,array[i]}' | sort -k 2 -n -r | head -10 beam.smp 84188 systemd-journal 59880 dockerd 55516 rsyslogd 40840 firewalld 29924 containerd 29440 tuned 18540 barad_agent 14076 iscsid 10124 polkitd 9500具體腳本如下:
#!/usr/bin/bash # Author: hushang # Created Time: 2021-09-09 21:32 # Script Description: 統計使用內容最大的前十個進程memory(){# 首先創建一個臨時文件,然后將top命令輸出的內容保存至臨時文件中memory_temp_file=`mktemp memory_use.XXXX`top -b -n 1 > $memory_temp_file# 統計內存使用情況tail -n +8 $memory_temp_file | awk '{array[$NF]=$6}END{for (i in array) print array[i],i}' | sort -k 1 -n -r | head -10# 刪除臨時文件rm -f $memory_temp_file }memory# 結果如下 [root@VM-8-7-centos shell_05]# bash memory_use2.sh 84188 beam.smp 61240 systemd-journal 55516 dockerd 41532 rsyslogd 29924 firewalld 29440 containerd 18540 tuned 14076 barad_agent 10124 iscsid 9500 polkitd# 如果的統計cpu的話 改變一個字段即可 將awk命令中的$6 變為 $9 即可總結
以上是生活随笔為你收集整理的shell脚本:介绍、语法、运算、流程控制、对文件/输出流处理、案例的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 一文读懂数据治理怎么做
- 下一篇: 电影推荐