1. 程式人生 > 實用技巧 >linux和bash實戰

linux和bash實戰

指令碼與函式

花括號括起來的一段shell命令

#錯誤寫法
[[email protected] ~]$ cpu_mem(){top -b  -n 1 -d 1 | grep -i aliyundun$ | awk '{print $9,$10}'; }
-bash: 未預期的符號 `{top' 附近有語法錯誤
#錯誤寫法
[[email protected] ~]$ cpu_mem(){ top -b  -n 1 -d 1 | grep -i aliyundun$ | awk '{print $9,$10}' }
>
#正確的單行寫法
cpu_mem(){ top -b  -n 1 -d 1 | grep -i aliyundun$ | awk '{print $9,$10}'; }

#多行寫法
cpu_mem(){ 
  top -b  -n 1 -d 1 | grep -i aliyundun$ | awk '{print $9,$10}'; 
}

#引數化
cpu_mem(){ top -b  -n 1 -d 1 | grep -i "$1" | awk '{print $9,$10}';}

bash_profile作用

# .bash_profile

# Get the aliases and functions
if [ -f ~/.bashrc ]; then
        . ~/.bashrc
fi

# User specific environment and startup programs
PATH=$PATH:$HOME/bin

export PATH

cpu_mem ()
{
    top -b -n 1 -d 1 | grep --color=auto -i "$1" | awk '{print $9,$10}'
}
  • .bash_profile 每次shell啟動都會預設載入
  • PATH變數是預設找命令的地址 /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin

三劍客演練

分類統計

[[email protected] ~]$ echo '
a 1
a 2
a 3
b 4
b 5
b 6
' | awk '{d[$1]+=$2}END{for(k in d) print k,d[k]}'
 0
a 6
b 15
[[email protected] ~]$ echo '
a 1
a 2
a 3
b 4
b 5
b 6
' | awk '{print "d["$1"]+="$2}'
d[]+=
d[a]+=1
d[a]+=2
d[a]+=3
d[b]+=4
d[b]+=5
d[b]+=6
d[]+=
[[email protected] ~]$

awk與python的對比

def test_awk():
    # awk預設詞典不用初始化
    time = {}
    count = {}
    # awk把每行拆分為一個個的記錄,其實就是包含每條記錄的列表
    # awk通過$1 $2把每個記錄又拆分成了小列表
    data = [
        ["a", 1],
        ["a", 2],
        ["a", 3],
        ["b", 4],
        ["b", 5],
        ["b", 6]
    ]

    for record in data:
        # 對應$1
        k1 = record[0]
        # 對應$2
        k2 = record[1]
        # awk預設不用做初始化
        if k1 not in time:
            time[k1] = 0

        # 等價於 d[$1] += $2
        time[k1] += k2

        if k1 not in count:
            count[k1] = 0
        count[k1] += 1

    # 對應 for(k in d) print k,d[k]  寫法基本一致
    for k in time:
        print(f"k={k}, avg={time[k] / count[k]}")

精簡版python程式碼

def test_awk_mini():
    time, count = {}, {}
    data = [
        ["a", 1],
        ["a", 2],
        ["a", 3],
        ["b", 4],
        ["b", 5],
        ["b", 6]
    ]
    for record in data:
        time.setdefault(record[0], 0)  # todo: 型別判斷 string預設為"" int預設為0
        time[record[0]] += record[1]
        count.setdefault(record[0], 0)
        count[record[0]] += 1

    # 對應 for(k in d) print k,d[k]  寫法基本一致
    for k in time:
        print(f"k={k}, avg={time[k] / count[k]}")

awk程式碼

#     echo '
# a 1
# a 2
# a 3
# b 4
# b 5
# b 6
# ' | awk '{d[$1]+=$2}END{for(k in d) print k,d[k]}'

找出狀態碼第9位為404和500的錯誤日誌,
less nginx.log | awk '$9=="404" || $9 == "500"'
awk '$9=="404" || $9 == "500"' nginx.log|less
awk '$9~/404|500/' nginx.log | less
正則表示式 : awk '$9=="404" || $9 == "500" {print $9}' nginx.log
不斷計數: awk '$9~/404|500/{t+=1}END{print t}' nginx.log 
awk和sed、grep等都可以跟檔名,使用正則時,awk可直接跟正則表示式,但是sed和grep要加-E


並統計錯誤日誌的行數


less nginx.log | awk '{print $9}'| grep -E '500|404' | wc -l
less nginx.log | awk '$9=="404" || $9 == "500"' | wc -l
正則表示式 : awk '$9=="404" || $9 == "500" {print $9}' nginx.log
不斷計數: awk '$9~/404|500/{t+=1}END{print t}' nginx.log 

取出最大的響應時間 max_response_time()

max_response_time ()
{
    less nginx.log | awk '{print $(NF-1)}' | sort -nr | head -1
}

取出top3的響應時間,並打印出對應的url max_response_time_and_url()

max_response_time_and_url ()
{
    less ~/nginx.log | awk '{print $(NF-1), $7}' | sort -rn | head -3
}

取出全部請求的平均響應時間 avg_response_time()

avg_response_time ()
{
    less nginx.log | awk '{sum+=$(NF-1)}END{print sum/NR}'
}

取出所有相同url請求的平均響應時間,並且按照響應時間排序取出top 3 avg_response_time_by_url()

avg_response_time_by_url ()
{
    less nginx.log | awk '{time[$7]+=$(NF-1); count[$7]+=1;}END{for(k in time) print time[k]/count[k], k}' | sort -nr | head -3
}

統計每個url的頂層路由地址所對應的qps qps_by_route()

比如

[05/Dec/2018:00:00:01 +0000] /topics/17112 
[05/Dec/2018:00:00:02 +0000] /topics?page=63

計算/topics的平均qps 每秒多少次請求,列印平均qps最高的top5的頂級路由

/topics 100
/cable 80
less nginx.log | 
  awk '{print $4,$7}' | 
  sed 's#[?!].*##' |
  sed -E 's#([^ ]*) *(/[^/]*).*#\1:\2#'  |
  sort | 
  awk -F: '
{cur=($3*60+$4);}
NR==1{min=cur; max=cur;}
NR>1{
count[$NF]+=1; 
if(cur<min) min=cur; 
if(cur>max) max=cur;
}
END{
for(k in count) print k,count[k]/(max-min+1)}
' | 
  sort -k2 -nr | head -5

程序與網路

每隔1s統計下aliyundun的2個程序的cpu與mem,分類彙總下10s內的平均cpu與響應時間 avg_cpu_mem_py_process()

top -b -d 1 -n 10 | grep -i aliyundun | awk '{cpu[$NF]+=$(NF-3);mem[$NF]+=$(NF-2);count[$NF]+=1}END{for(k in cpu) print k, cpu[k]/count[k], mem[k]/count[k]}'

統計當前伺服器上每個監聽埠對應的網路狀態的數量 connections_summary()

netstat  -tn | sed 1,2d | awk '{print $4, $NF}' | awk -F: '{print $NF}' | sort | uniq -c

微信朋友圈

friend() {
    while true; do
        #獲取介面,提取暱稱和朋友圈內容
        adb shell 'uiautomator dump && cat /sdcard/window_dump.xml' |
            sed 's#><#>|<#g' |
            awk 'BEGIN{RS="|"}{print $0}' |
            awk -F\" '
            BEGIN{OFS="\t"}
            /e3x/{name=$4}
            /b_e/{msg=$4;print name,"|",msg}
            '
        #取出大概的滑動距離
        distance=$(
            adb shell wm size |
                awk -F' |x' '
                {
                    width=$(NF-1);
                    height=$NF;
                    print width*0.5, height*0.8, width*0.5, height*0.2}'
        )
        #利用input直接劃屏
        adb shell input swipe $distance
    done
}