Shell從入門到精通

熟悉基本shell操做不只是運維的基本功,對於開發來講也是多多益善,我在學習的過程當中,總結了十個練手的小demo,並附上涉及的知識點,僅供娛樂。html


1. 多線程ping監控,檢查同一網段的IP是否連通

  • Linux 系統中有一個特殊的設備/dev/null,這是一個黑洞。不管往該文件中寫入多少數據,都會被系統吞噬、丟棄。若是有些輸出信息是咱們再也不須要的, 則可使用重定向將輸出信息導入該設備文件中。注意:數據一旦導入黑洞將沒法找回。
  • 重定向: > 是覆蓋重定向, >> 是累加劇定向
  • $0 這個程式的執行名字
    $n 這個程式的第n個參數值,n=1..9
    $* 這個程式的全部參數,此選項參數可超過9個。
    $# 這個程式的參數個數
    $$ 這個程式的PID(腳本運行的當前進程ID號)
    $! 執行上一個背景指令的PID(後臺運行的最後一個進程的進程ID號)
    $? 執行上一個指令的返回值 (顯示最後命令的退出狀態。0表示沒有錯誤,其餘任何值代表有錯誤)
    $- 顯示shell使用的當前選項,與set命令功能相同
    $@ 跟$*相似,可是能夠看成數組用
  • &  表示任務在後臺執行,如要在後臺運行redis-server,則有  redis-server &
    && 表示前一條命令執行成功時,才執行後一條命令 ,如 echo '1‘ && echo '2'
    | 表示管道,上一條命令的輸出,做爲下一條命令參數,如 echo 'yes' | wc -l
    || 表示上一條命令執行失敗後,才執行下一條命令,如 cat nofile || echo "fail"redis

  • ping 命令語法shell

    ping [-dfnqrRv][-c<完成次數>][-i<間隔秒數>][-I<網絡界面>][-l<前置載入>][-p<範本樣式>][-s<數據包大小>][-t<存活數值>][主機名稱或IP地址]
#!/bin/bash
#使用&開啓後臺進程
net="101.200.35"

mult_ping() {
        ping -c2 -i0.2 -W1 $1 &>/dev/null
        if [ $? -eq 0 ];then
                echo "$1 is up"
        else
                echo "$1 is down"
        fi
}

for i in {0..255}
do
        mult_ping $net.$i &
done
wait

2.進度條功能顯示

  • 常見系統預設變量
#!/bin/bash

trap 'kill $!' INT
# 定義寬度爲50的進度條
# 輸出完成後將/r光標切換到行首,準備下一次進度條顯示
bar () {
        while :
                pound=""
                for ((i = 47; i>=1; i-- ))
                do      
                        pound += #
                        printf "|%s%${i}s|\r" "$pound"
                        sleep 0.2
                done    
                
        }       
        
# 調用函數,顯示進度符號,直到複製結束kill進度函數
bar &
cp -r $1 $2
kill $!
echo "複製結束"

3. Linux建立進程的三種方式

  1. fork
    一般狀況下在系統中經過相對路徑或絕對路徑執行一個命令時,都會由父進程開啓一個子進程,當子進程結束後再返回父進程,這種行爲過程就叫做fork。當腳本中正常調用一個外部命令 1或其餘腳本時,都會fork一個子Shell進程,咱們的命令會運行在這個子Shell中。
  2. exec
    使用 exec 方式調用其餘命令或腳本時,系統不會開啓子進程,而是使用新的程序替換當前的 Shell 環境,由於當前 Shell 環境被替換了,因此當 exec 調用的程序結束後,當前環境會被關閉。可是有一個特例,當 exec 後面的參數是文件重定向時,不會替換當前 Shell 環境,腳本後續的其餘命令也不會受到任何影響。
  3. source或 . (點)
    使用 source 命令或.(點)能夠不開啓子 Shell,而在當前 Shell 環境中將須要執行的命令加載進來,執行完加載的命令後,繼續執行腳本中後續的指令。

分析工具:pstree 進程樹數組

4. 控制進程數量——文件描述符和命名管道

文件描述符

文件描述符是一個非負整數,而內核須要經過這個文件描述符才能夠訪問文件。當咱們在系統中打開已有的文件或新建文件時,內核每次都會給特定的進程返回一個文件描述符,當進程須要對文件進行讀或寫操做時,都要依賴這個文件描述符進行。文件描述符就像一本書的目錄頁數(也叫索引),經過這個索引能夠找到須要的內容。在 Linux 或類 UNIX系統中內核默認會爲每一個進程建立三個標準的文件描述符,分別是 0(標準輸入)、 1(標準輸出)和 2(標準錯誤)。經過查看/proc/PID 號/fd/目錄下的文件,就能夠查看每一個進程擁有的全部文件描述符。bash

建立文件描述符:網絡

exec 文件描述符 <> 文件名

調用文件描述符語法格式:多線程

&文件描述符

關閉文件描述符:併發

exec 文件描述符<&-
exec 文件描述符>&-

命名管道

管道是進程間通訊的一種方式,匿名管道,使用|符號就能夠建立一個匿名管道,顧名思義,系統會自動建立一個能夠讀寫數據的管道,可是這個管道並無名稱。一個程序往管道中寫數據,另外一個程序就能夠從管道中讀取數據。可是匿名管道僅能夠實現父進程與子進程之間的數據交換,能不能實現任意兩個無關的進程之間的通訊呢?答案是確定的,使用命名管道,也叫FIFO1文件。運維

命名管道的特徵:curl

  •  FIFO 文件由命令建立(mknod 或 mkfifo 命令),能夠在文件系統中直接看到。
  • 寫入管道的數據一旦被讀取後,就不能夠再重複讀取。
  • 進程往命名管道中寫數據時,若是沒有其餘進程讀取數據,則寫進程會被阻塞。
  • 進程嘗試從命名管道中讀取數據時,若是管道中沒有數據,則讀進程會被阻塞。
  • 命名管道中的數據常駐內存,並不實際寫入磁盤,讀寫效率會更高。

5. 可任意控制進程數量的多線程ping

第一個demo中,經過 & 開啓任意數量線程進行ping,可是這裏的線程不可控。咱們用上面的文件描述符和命名管道的知識,寫一段可控的多線程ping。

#!/bin/bash
  
pipefile=/tmp/procs_$$.temp
num=10
net="101.200.35"

multi_ping() {
        ping -c2 -i0.2 -W1 $1 &>/dev/null
        if [ $? -eq 0 ];then
                echo "$1 is up"
        else
                echo "$1 is down"
        fi
}
# 建立命名管道文件,建立其文件描述符,經過重定向將數據導入管道文件
mkfifo $pipefile
exec 12<>$pipefile
for i in `seq $num`
do
        echo "" >&12 &
done
# 成功讀取命名管道中的數據後開啓新的進程
# 全部內容讀取完以後read被阻塞,沒法再啓動新的進程
# 等待前面啓動的線程結束後,繼續往管道文件中寫入數據,釋放阻塞,再次開啓新的線程
for j in {1..254}
do
        read -u12
        {
                multi_ping $net.$j
                echo "" >&12
        } &
done
wait
rm -rf $pipfile

6. sed爬蟲批量下載美女圖片

  • sed命令彙總




  • sed 是逐行處理軟件,咱們可能僅輸入了一條 sed 指令,但系統會將該指令應用在全部匹配的數據行上,所以相同的指令會被反覆執行 N 次,這取決於匹配到的數據有幾行。
  • 默認 sed 不支持擴展正則,若是但願使用擴展正則匹配數據,可使用-r 參數。
  • sed 程序使用=指令能夠顯示行號,結合條件匹配,能夠顯示特定數據行的行號。
  • 在 sed 中支持使用感嘆號(!)對匹配的條件進行取反操做。

下載思路:用curl獲取網站源代碼+sed數據清洗獲取圖片地址+wget下載保存

#!/bin/bash
# 爬取美女圖片

# 定義要爬取的網站和保存的文件
page="https://tieba.baidu.com/p/4420470629"
URL="beau.txt"
# 將網站源代碼保存到文件中
curl -s https://tieba.baidu.com/p/4420470629 > $URL
# 對源代碼數據過濾清洗,獲取種子的URL連接
echo -e "\033[32m 正在獲取種子 URL,請稍後...\033[0m"
sed -i '/<img/!d' $URL #刪除不包含<img 的行
sed -i 's/.*src="//' $URL #刪除 src="及其前面的全部內容
sed -i 's/".*//' $URL #刪除雙引號及其後面的全部內容
echo

#利用循環批量下載全部圖片數據
#wget 爲下載工具,其參數選項描述以下:
# -P 指定將數據下載到特定目錄(prefix)
# -c 支持斷點續傳(continue)
# -q 不顯示下載過程(quiet)
echo -e "\033[32m 正在批量下載種子數據,請稍後...\033[0m"
for i in $(cat $URL)
do
        wget -P tempPhoto/ -c $i
done

這種知識最基本的爬蟲,對於反爬蟲的網站就嗝屁了,對於那種異步加載的也沒辦法,總之,就是比較弱。

7. sed隨機點名器

作一個互聯網大佬的隨機點名器

#!/bin/bash
#按 Ctrl+C 組合鍵時:恢復光標,恢復終端屬性,清屏,退出腳本
#防止程序意外中斷致使的終端混亂
trap 'tput cnorm;stty $save_property;clear;exit' 2
#定義變量:人員列表文件名,文件的行數,屏幕的行數,屏幕的列數
name_file="name.txt"
line_file=$(sed -n '$=' $name_file)
line_screen=`tput lines`
column_screen=`tput cols`
#設置終端屬性
save_property=$(stty -g) #保存當前終端全部屬性
tput civis #關閉光標
#隨機抽取一我的名(隨機點名)
while :
do
        tmp=$(sed -n "$[RANDOM%line_file+1]p" $name_file)
        #隨機獲取文件的某一行人名
        tput clear #清屏
        tput cup $[line_screen/4] $[column_screen/4]
        echo -e "\033[3;5H 隨機點名器(按 P 中止): "
        echo -e "\033[4;5H#############################"
        echo -e "\033[5;5H# #"
        echo -e "\033[6;5H#\t\t$tmp\t\t#"
        echo -e "\033[7;5H# #"
        echo -e "\033[8;5H#############################"
        sleep 0.1
        stty -echo
        read -n1 -t0.1 input
        if [[ $input == "p" || $input == "P" ]];then
                break
        fi
done
tput cnorm #恢復光標
stty $save_property #恢復終端屬性

8.系統性能監控腳本

  • awk語法格式
  • awk變量
  • awk條件匹配
  • awk 能夠經過-v(variable) 選項設置或者修改變量的值,咱們可使用-v 定義新的變量,也可使用該選項修改內置變量的值。
  • 使用[]定義分隔符集合,同時設置多個分隔符。好比使用[:,-]表示以冒號(:)、逗號(,)或者橫線(-)爲分隔符
  • [-F|-f|-v]   大參數,-F指定分隔符,-f調用腳本,-v定義變量 var=value

 

9.監控網絡鏈接狀態

  • ss語法格式
#!/bin/bash
# 監控網絡鏈接狀態
#全部 TCP 鏈接的個數
TCP_Total=$(ss -s | awk '$1=="TCP"{print $2}')
#全部 UDP 鏈接的個數
UDP_Total=$(ss -s | awk '$1=="UDP"{print $2}')
#全部 UNIX sockets 鏈接個數
Unix_sockets_Total=$(ss -ax | awk 'BEGIN{count=0} {count++} END{print
count}')
#全部處於 Listen 監聽狀態的 TCP 端口個數
TCP_Listen_Total=$(ss -antlpH | awk 'BEGIN{count=0} {count++} END{print
count}')
#全部處於 ESTABLISHED 狀態的 TCP 鏈接個數
TCP_Estab_Total=$(ss -antpH | awk 'BEGIN{count=0} /^ESTAB/{count++}
END{print count}')
#全部處於 SYN-RECV 狀態的 TCP 鏈接個數
TCP_SYN_RECV_Total=$(ss -antpH | awk 'BEGIN{count=0} /^SYN-RECV/{count++}
END{print count}')
#全部處於 TIME-WAIT 狀態的 TCP 鏈接個數
TCP_TIME_WAIT_Total=$(ss -antpH | awk 'BEGIN{count=0} /^TIME-WAIT/{count++}
END{print count}')
#全部處於 TIME-WAIT1 狀態的 TCP 鏈接個數
TCP_TIME_WAIT1_Total=$(ss -antpH | awk 'BEGIN{count=0}
/^TIME-WAIT1/{count++} END{print count}')
#全部處於 TIME-WAIT2 狀態的 TCP 鏈接個數
TCP_TIME_WAIT2_Total=$(ss -antpH | awk 'BEGIN{count=0}
/^TIME-WAIT2/{count++} END{print count}')
#全部遠程主機的 TCP 鏈接次數
TCP_Remote_Count=$(ss -antH | awk '$1!~/LISTEN/{IP[$5]++} END{ for(i in
IP){print IP[i],i} }' | sort -nr)
#每一個端口被訪問的次數
TCP_Port_Count=$(ss -antH | sed -r 's/ +/ /g' | awk -F"[ :]"
'$1!~/LISTEN/{port[$5]++} END{for(i in port){print port[i],i}}' | sort -nr)
#定義輸出顏色
SUCCESS="echo -en \\033[1;32m" #綠色
NORMAL="echo -en \\033[0;39m" #黑色
#顯示 TCP 鏈接總數
tcp_total(){
        echo -n "TCP 鏈接總數: "
        $SUCCESS
        echo "$TCP_Total"
        $NORMAL
} 
#顯示處於 LISTEN 狀態的 TCP 端口個數
tcp_listen(){
        echo -n "處於 LISTEN 狀態的 TCP 端口個數: "
        $SUCCESS
        echo "$TCP_Listen_Total"
        $NORMAL
} 
#顯示處於 ESTABLISHED 狀態的 TCP 鏈接個數
tcp_estab(){
        echo -n "處於 ESTAB 狀態的 TCP 鏈接個數: "
        $SUCCESS
        echo "$TCP_Estab_Total"
        $NORMAL
} 
#顯示處於 SYN-RECV 狀態的 TCP 鏈接個數
tcp_syn_recv(){
        echo -n "處於 SYN-RECV 狀態的 TCP 鏈接個數: "
        $SUCCESS
        echo "$TCP_SYN_RECV_Total"
        $NORMAL
} 
#顯示處於 TIME-WAIT 狀態的 TCP 鏈接個數
tcp_time_wait(){
        echo -n "處於 TIME-WAIT1 狀態的 TCP 鏈接個數: "
        $SUCCESS
        echo "$TCP_TIME_WAIT1_Total"
        $NORMAL
} 
#顯示處於 TIME-WAIT2 狀態的 TCP 鏈接個數
tcp_time_wait2(){
        echo -n "處於 TIME-WAIT2 狀態的 TCP 鏈接個數: "
        $SUCCESS
        echo "$TCP_TIME_WAIT2_Total"
        $NORMAL
} 
#顯示 UDP 鏈接總數
udp_total(){
        echo -n "UDP 鏈接總數: "
        $SUCCESS
        echo "$UDP_Total"
        $NORMAL
} 
#顯示 UNIX sockets 鏈接總數
unix_total(){
        echo -n "Unix sockets 鏈接總數: "
        $SUCCESS
        echo "$Unix_sockets_Total"
        $NORMAL
} 
#顯示每一個遠程主機的訪問次數
remote_count(){
        echo "每一個遠程主機與本機的併發鏈接數: "
        $SUCCESS
        echo "$TCP_Remote_Count"
        $NORMAL
} 
#顯示每一個端口的併發鏈接數
port_count(){
        echo "每一個端口的併發鏈接數: "
        $SUCCESS
        echo "$TCP_Port_Count"
        $NORMAL
}

print_info(){
        echo -e "------------------------------------------------------"
        $1
}
print_info tcp_total
print_info tcp_listen
print_info tcp_estab
print_info tcp_syn_recv
print_info tcp_time_wait
print_info tcp_time_wait1
print_info tcp_time_wait2
print_info udp_total
print_info unix_total
print_info remote_count
print_info port_count
echo -e "------------------------------------------------------"

 

 

參考

相關文章
相關標籤/搜索