跟着360架構師學shell

1. 變量替換

  • ${變量名#匹配規則}  從頭開始匹配,最短刪除
  • ${變量名##匹配規則}  從頭開始匹配,最長刪除
  • ${變量名%匹配規則}  從尾開始匹配,最短刪除
  • ${變量名%%匹配規則}  從尾開始匹配,最長刪除
  • ${變量名/舊字符串/新字符串}  替換舊的字符串爲新字符串,只替換第一個
  • ${變量名//舊字符串/新字符串}  替換舊的字符串爲新字符串,替換全部
例:
variable_1="i love u, do you love me"

echo ${variable_1#*ov}
# e u, do you love me

echo ${variable_1##*ov}
# e me

echo ${variable_1%ov*}
# i love u, do you l

echo ${variable_1%%ov*}
# i l

echo ${variable_1/ov/bb}
# i lbbe u, do you love me

variable_1="i love u, do you love me"
variable_2=${variable_1/ov/bb}
echo $variable_2
# i lbbe u, do you lbbe me

2. 字符串處理

2.1 獲取字符串長度

  • ${#string}
  • expr length "$string"
例:
variable_1="i love u, do you love me"
echo ${#variable_1}
expr length "$variable_1"

len=`expr length "$variable_1"`
echo $len

2.2 獲取子串在字符串中的索引位置

  • expr index "$string" "$substring"  [不是子串,而是子串切分紅單個字符,查找第一個出現的字符的位置]
例:
variable_1="i love u, do you love me"
variable_2="ov"
expr index "$variable_1" "$variable_2"
# 4

variable_2="ok"
expr index "$variable_1" "$variable_2"
# 4

2.3 獲取子串長度

  • expr match "string substring"  [必須從頭開始匹配,能匹配到的子串返回長度,支持正則]
例:
variable_1="quickstart is a app"

echo `expr match "$variable_1" app`
# 0

echo `expr match "$variable_1" quick`
# 5

echo `expr match "$variable_1" quick.`
# 6

echo `expr match "$variable_1" quick.*`
# 19

2.4 子串抽取

  • ${string:position}  從string的position位置開始
  • ${string:position:length}  從position位置開始抽取length長度
  • ${string:-position}  從右邊開始匹配
  • ${string:(position)}  從左邊開始匹配
  • expr substr "$string" "$position" "$length"  從position位置開始抽取length長度,索引從0開始

注意:${string:position}索引從1開始,而 expr 索引從0開始java

例:
variable_1="i love u, do you love me"
position=4
length=4
echo ${variable_1:position}
# ve u, do you love me

echo ${variable_1:position:length}
# ve u

echo ${variable_1: -position}
# e me

echo ${variable_1:(-position)}
# ve u, do you love me

echo ${variable_1:(-position)}
# e me

variable_2=`expr substr "$variable_1" "$position" "$length"`
echo $variable_2
# ove

3. 字符串練習

string="bigdata process framework is hadoop, hadoop is an open source project"

執行腳本後,打印輸出string字符串變量,並給出用戶如下選項:
(1) 打印string長度
(2) 在整個字符串中刪除Hadoop
(3) 替換第一個Hadoop爲Mapreduce
(4) 替換所有Hadoop爲Mapreduce
用戶輸入對應的數字會執行相應的功能,輸入q|Q退出操做
#!/bin/bash
string="Bigdata process framework is Hadoop,Hadoop is an open source project"

function print_tips {
    echo "******************************************"
    echo "***  (1) 打印string長度"
    echo "***  (2) 在整個字符串中刪除Hadoop"
    echo "***  (3) 替換第一個Hadoop爲Mapreduce"
    echo "***  (4) 替換所有Hadoop爲Mapreduce"
    echo "******************************************"
}

function print_len {
    echo "${#string}"
}

function del_Hadoop {
    echo "${string//Hadoop/}"
}

function rep_Hadoop_to_Mapreduce_first {
    echo "${string/Hadoop/Mapreduce}"
}

function rep_Hadoop_to_Mapreduce_alll {
    echo "${string//Hadoop/Mapreduce}"
}

while true
do
    echo
    echo
    echo "【string=$string】"
    print_tips

    read -p "please input your choice(1|2|3|4|q|Q): " choice

    case $choice in
            1)
                    echo
                    print_len
                    ;;
            2)
                    echo
                    del_Hadoop
                    ;;
            3)
                    echo
                    rep_Hadoop_to_Mapreduce_first
                    ;;
            4)
                    echo
                    rep_Hadoop_to_Mapreduce_alll
                    ;;
            q|Q)
                    exit
                    ;;
            *)
                    echo
                    echo "error input!"
                    ;;
    esac
done

4. 命令替換

  • `command`
  • $(command)

$(())主要用來進行整數運算,包括加減乘除node

例1:獲取系統中的全部用戶並輸出(/etc/passwd)
cat /etc/passwd | cut -d ":" -f 1

#!/bin/bash

index=1

for user in `cat /etc/passwd | cut -d ":" -f 1`
do
    echo "this is $index user: $user"
    index=$(($index+1))
done
例2:根據系統時間計算今年、明年
echo "this is $(date +%Y), next year is $(($(date +%Y)+1))"
例3:根據系統時間獲取今年還剩下多少個星期,已通過了多少個星期
echo "今年已通過了$(date +%j)天,合$(($(date +%j) / 7))周,還剩下$(((365-$(date +%j)) / 7))周"
例子4:判斷nginx進程是否存在,不存在的話拉起該進程
#!/bin/bash

nginx_process_num=$(ps -ef | grep nginx | grep -v grep | wc -l)
if [ $nginx_process_num -eq 0 ]; then
    systemctl start nginx
fi

5. 有類型變量

  • declare、typeset
-r 只讀
-i 整數
-a 數組
-f 在腳本中顯示定義的函數和函數體
-F 在腳本中顯示定義的函數
-x 環境變量

若是要取消類型聲明,減號變加號就好了python

例:
declare -r variable_1="hello java"
variable_1="abc"

num1=10
echo $num1+1

declare -i num2=10
declare -i num3
num3=$num2+1

echo $num2+1
echo $num3

declare -f
declare -F

array=("jane" "jone" "jack" "jordan")
輸出數組內容
    echo ${array[@]}    輸出全部內容
    echo ${array[0]}    輸出下標對應的內容
獲取數組長度
    echo ${#array}
    echo ${#array[0]}

6. 數字運算

  • expr $num1 operator $num2
  • $(($num1 operator $num2))

注意:expr只支持整型運算mysql

  • expr 操做符
num1 | num2     num1不爲空且不爲0,返回num1,不然返回num2
num1 & num2     num1不爲空且不爲0,返回num1,不然返回0
num1 < num2     num1小於num2,返回1,不然返回0
num1 <= num2    num1小於等於num2,返回1,不然返回0
num1 = num2     num1等於num2,返回1,不然返回0
num1 != num2    num1不等於num2,返回1,不然返回0
num1 > num2     num1大於num2,返回1,不然返回0
num1 >= num2    num1大於等於num2,返回1,不然返回0
num1 + num2
num1 - num2
num1 * num2
num1 / num2
num1 % num2
例:
num1=10
num2=20

expr $num1 + $num2
echo $(($num1 + $num2))

expr $num1 \| $num2
expr $num1 \& $num2
expr $num1 \> $num2
expr $num1 \>= $num2
expr $num1 \< $num2
expr $num1 \<= $num2
expr $num1 = $num2
expr $num1 + $num2
expr $num1 - $num2
expr $num1 \* $num2
expr $num1 / $num2
expr $num1 % $num2
練習:提示用戶輸入一個正整數num,而後計算1+2+3+...+num的值,必須判斷num是否爲正整數,不符合容許再次輸入
#!/bin/bash

sum=0
while true
do
    read -p "please input: " num
    expr $num + 1 &> /dev/null

    if [ $? -eq 0 ]; then
        if [ `expr $num \> 0` -eq 1 ]; then

            for ((i=0;i<=$num;i++))
            do
                sum=$(($sum + $i))
            done

            echo $sum
            exit
        else
            echo "小於等於0"
            continue
        fi
    else
        echo "不是整數"
        continue
    fi
done

7. 函數定義和使用

7.1 函數定義

function name {
}
name() {
}
例:寫一個nginx的守護腳本
#!/bin/bash

this_pid=$$
while true
do
        ps -ef | grep nginx | grep -v grep | grep -v $this_pid &> /dev/null
        if [ $? -eq 0 ]; then
                echo "nginx is running well!"
                sleep 3
        else
                echo "starting!"
                systemctl nginx start
                sleep 1
        fi
done

7.2 傳遞參數

例:寫一個腳本支持+-*/四種運算
#!/bin/bash

function cal {
    case $2 in
        +)
            echo $(($1 + $3))
            ;;
        -)
            echo $(($1 - $3))
            ;;
        \*)
            echo $(($1 * $3))
            ;;
        /)
            echo $(($1 / $3))
            ;;
        *)
            echo "error input!"
            ;;
    esac
}

cal $1 $2 $3

7.3 返回值

  • return返回值,只能返回1-255以內的整數。使用return返回值,一般供其餘地方調用獲取狀態,所以一般返回0或者1,0表示成功,1表示失敗。return表示return 0
  • echo返回值,能夠返回任何字符結果,一般用於返回數據,好比一個字符串或列表值
例:
#!/bin/bash

this_pid=$$
function is_nginx_running {
    
    ps -ef | grep nginx | grep -v grep | grep -v $this_pid &> /dev/null

    if [ $? -eq 0 ]; then
        return
    else
        return 1
    fi
}

is_nginx_running && echo "nginx is running" || echo "nginx is down"

sh -x nginx_stat.sh        [-x能夠查看執行過程]

#!/bin/bash
function get_user_list {
    users=$(cat /etc/passwd | cut -d ":" -f1)
    echo $users
}

index=1
user_list=$(get_user_list)
for u in $user_list
do
    echo "this is the $((index++)) user: $u"
done

7.4 變量

  • 使用local定義變量表示局部變量,不然通常的變量都是全局變量
  • 函數內部的變量若是跟外部變量同名,則函數內部的變量替換外部的變量

7.5 函數庫

例:定義一個函數庫,該函數庫實現如下幾個函數
(1)加法函數 add
(2)減法函數 reduce
(3)乘法函數 multiple
(4)除法函數 dived
(5)打印系統運行狀況的函數sys_load,該函數能夠顯示系統內存運行狀況
base_function.lib

#!/bin/echo
function add {
    echo "`expr $1 + $2`"
}
function reduce {
    echo "`expr $1 - $2`"
}
function multiple {
    echo "`expr $1 \* $2`"
}
function divide {
    echo "`expr $1 / $2`"
}
function sys_load {
    echo "---memory info---"
    free -m

    echo
    echo "---disk info---"
    df -h
}
calculate.sh

#!/bin/bash
. /root/script/base_function.lib

add 1 2
reduce 11 33
multiple 3 44
divide 20 2
sys_load
  • 庫文件的後綴是任意的,可是通常以.lib使用
  • 庫文件一般沒有執行權限

8. 經常使用查找命令

8.1 find [路徑] [選項] [操做]

選項
-name                根據名字
-iname                根據名字,不區分大小寫
-perm                根據權限
-prune                該選項能夠排除某些查找目錄
-user                 根據文件用主
-group                根據文件屬組
-mtime -n|+n  根據文件更改時間,-n表示n天之內修改的文件,+n表示n天意外修改的文件
-mmin -n|+n   根據文件更改時間,-n表示n分鐘之內修改的文件,+n表示n分鐘意外修改的文件
-newer file1 ! file2     比file1新可是比file2舊的文件
-type                 根據文件類型    f-文件,d-目錄,l-管道文件
-size -n +n             根據文件大小
-mindepth n             從n級子目錄開始搜索
-maxdepth n             最多搜索到n級子目錄
-a                 與
-o                 或
!|-not                 非
操做
-print         默認操做
-exec        對搜索到的文件執行特定操做,格式爲 -exec command {} \; ,其中{}表明搜索到的文件,如:find . -name "*.conf" -exec rm -rf {} \;
-ok        跟-exec同樣,只是每次操做都會給用戶提示
例:將/var/log目錄下以log結尾,且更改時間在7天以上的刪除
find /var/log -name "*log" -mtime +7 -exec rm -rf {} \;

8.2 locate which whereis

locate         不一樣於 find,find會查找整個磁盤,而locate命令會在數據庫中查找,只能查找單個文件。能夠用updatedb更新數據庫文件,該文件是 /var/lib/mlocate/locate.db
whereis        -b,只返回二進制文件,-m,只返回幫助文檔文件,-s,只返回源碼文件
which         只查找二進制文件

9. grep

  • grep [option] [pattern] [file1,file2]
  • command | grep [option] [pattern]
參數
-i     不區分大小寫
-v     反向選擇
-n     顯示行號
-r     遞歸
-E     支持擴展正則表達式
-F     不按正則表達式,按字符串字面匹配
-x     匹配整行
-w     匹配整詞
-c     只輸出匹配到的總行數,不顯示具體內容
-l     只列出文件,不顯示具體內容
例:grep -E "python|PYTHON" file

egrep 和 grep -E 等價nginx

10. sed(stream editor縮寫)

10.1 sed

  • sed [option] "pattern command" file
  • stdout | sed [option] "pattern command" file
option
-n     只打印模式匹配行。sed -n "/python/p" sed.txt
-e     直接在命令行編輯。sed -n -e "/PYTHON/p" -e "/python/p" sed.txt,多重處理的時候用-e鏈接
-f     指定編輯處理的 pattern command 內容。sed -n edit.sed sed.txt,edit.sed中的內容是/python/p
-r     pattern支持擴展正則表達式。sed -n -r "/python|PYTHON/p" sed.txt
-i     對源文件進行修改
例:替換文件中love爲like
sed -n "s/love/like/g;p" sed.txt
sed -i "s/love/like/g" sed.txt
pattern
10command            匹配第10行
10,20command            匹配第10-20行
10,+5command            匹配第10-16行
/pattern1/command        匹配pattern1的行。sed -n "/\/spool\//p" /etc/passwd,匹配帶有/spool/的行。sed -n "/^daemon/p" /etc/passwd,匹配daemon開頭的行
/pattern1/,/pattern2/command     匹配pattern1到pattern2的行結束。sed -n "/^daemon/p" /etc/passwd
10,/pattern1/command        從第10行開始匹配到第一個pattern1的行結束
/pattern1/,10command        連續匹配10行
command
查詢
    p     打印
增長
    a     行後追加。sed -i "/\/bin\/bash/a this user can login to system" passwd
    i     行前追加
    r     外部文件讀入,行尾追加
    w     匹配行寫入外部文件
刪除
    d     刪除不能登陸的用戶,sed -i "/\/sbin\/nologin/d" passwd。刪除從mail開頭的行到ftp開頭的行,sed -i "/^mail/,/^ftp/d" passwd
    例:刪除配置文件中的全部空行和註釋行。sed -i "/^$/d;/[:blank:]*#/d;/\t/d" nginx.conf,[:blank:]匹配空格,\t匹配tab
    例:在配置文件中全部不以#開頭的行前面添加*符號(#開頭的行不添加)。sed -i "s/^\([^#]\)/\*\1/g" nginx.conf 或者 sed -i "s/^[^#]/*&/g" nginx.conf
更改
    s/old/new/         將行內第一個替換
    s/old/new/g     將行內全部替換
    s/old/new/2     將行內第二個替換
    s/old/new/2g     從第二個開始替換全部的
    s/old/new/ig     忽略大小寫
    例:刪掉全部的數字。sed -i "s/[0-9]+//g" sed.txt
其它
    =        顯示行號。sed -n "/\/sbin\/nologin/=" passwd

10.2 反向引用

  • & 和 1 引用模式匹配到的整個串(1的時候要替換的模式匹配中的串要用小括號包圍起來)
例:sed -i "s/had..p/&s/g" sed.txt   給能匹配到had..p的字符串後面加上s,hadoopx -> hadoopsx
sed -i "s/ha\(d..p\)/XX\1/g" sed.txt     給能匹配到had..p的d..p以外的串全替換成上XX,hadoopx -> XXdoopx
例:統計mysql配置文件各配置段的數量
#!/bin/bash

FILE_NAME=/root/script/my.cnf
function get_all_segament {
    sed -n '/\[.*\]/p' $FILE_NAME | sed -e "s/\[//g" | sed -e "s/\]//g"
    # 查找[開頭]結尾的行,而且刪除掉[和]
}

function get_all_segament_count {
    count=`sed -n "/\[$1\]/,/\[.*\]/p" $FILE_NAME | grep -v "^#" | grep -v "^$" | grep -v "\[.*\]" | wc -l`
    # 查找[$1]開頭的行到發現[.*]的行結束,去掉#開頭和空行,並去掉[.*]的行(即開頭和結束的行),統計數量
    echo $count
}

index=0
for segament in $(get_all_segament)
do
    index=`expr $index + 1`
    count=`get_all_segament_count $segament`
    echo "$index: $segament $count"
done

輸出:
1: client 1
2: mysql 1
3: mysqld 6
4: mysqldump 3

11. awk

  • awk 'BEGIN{}pattern{commands}END{}' file_name
  • stdout | 'BEGIN{}pattern{commands}END{}'
BEGIN{}        正式處理以前執行的
pattern     匹配模式
{commands}     執行命令(可能多行)
END{}         處理完全部的匹配數據以後執行

11.1 內置變量

$0        整行內容
$1-$n        本行中按照某個字符分隔後的第n個變量
NF        當前行的字段個數,也就是列的個數(Number Field)
NR         當前行的行號,從1開始計算(Number Row)
FNR        多文件處理時,每一個文件行號單獨計數,都是從1開始(File Number Row)
FS        輸入字段分隔符,不輸入默認是空格或者tab鍵分隔(Field Separator)
RS        輸入行分隔符。默認回車換行(Row Separator)
OFS        輸出字段分隔符。默認空格
ORS        輸出行分隔符。默認回車
FILENAME 處理的文件名
ARGC        命令行參數個數
ARGV        命令行參數數組
例:打印/etc/passwd文件的內容
awk '{print $0}' /etc/passwd
awk 'BEGIN{FS=":"}{print $1}' /etc/passwd
awk 'BEGIN{FS=":"}{print NF}' /etc/passwd
awk '{print NR}' /etc/passwd nginx.conf
awk '{print FNR}' /etc/passwd nginx.conf
awk 'BEGIN{RS="--"}{print $0}' test.txt
echo "a-b-c--d-e-f--g-h-i" | awk 'BEGIN{RS="--";FS="-"}{print $3}'
echo "a-b-c--d-e-f--g-h-i" | awk 'BEGIN{RS="--";FS="-";ORS="|";OFS="&"}{print $1,$2,$3}' #必須用逗號分隔,不然輸出字段分隔符不會起做用。a&b&c|d&e&f|g&h&i
awk '{print FILENAME}' nginx.conf #文件有多少行就會輸出多少次
awk '{print ARGC}' /etc/passwd test.txt

11.2 printf 格式化輸出

%s         打印字符串
%d         打印十進制數字
%x         打印十六進制
%f         打印浮點型
%o         打印八進制
%e         打印科學計數法
%c         打印ascii碼
-        左對齊
+         右對齊
#         顯示八進制在前面加0,十六進制在前面加0x
例:
awk 'BEGIN{FS=":"}{printf "%s\n",$1}' /etc/passwd
awk 'BEGIN{FS=":"}{printf "%-20s %-20s\n",$1,$7}' /etc/passwd
awk 'BEGIN{FS=":"}{printf "%#o\n",$3}' /etc/passwd

11.3 模式匹配的兩種方式

  • 正則表達式
  • 按關係運算符匹配
>
<
==        能夠用於數值和字符串
<=
>=
!=
~        匹配正則表達式
!~         不匹配正則表達式
&&
||
!
例:
匹配/etc/passwd中包含root的行。    awk '/root/{print $0}' /etc/passwd
匹配/etc/passwd中以root開頭的行。    awk '/^root/{print $0}' /etc/passwd

匹配/etc/passwd中第3個字段大於50的行。    awk 'BEGIN{FS=":"}$3>50{printf "%s\n",$0}' /etc/passwd

匹配/etc/passwd中第7個字段等於/sbin/nologin的行。    awk 'BEGIN{FS=":"}$7=="/sbin/nologin"{printf "%s\n",$7}' /etc/passwd

匹配/etc/passwd中第7個字段不等於/sbin/nologin的行。    awk 'BEGIN{FS=":"}$7!="/sbin/nologin"{printf "%s\n",$7}' /etc/passwd

匹配/etc/passwd中第3個字段包含三個以上數字的行(匹配正則表達式)。    awk 'BEGIN{FS=":"}$3~/[0-9]{3,}/{printf "%d\n",$3}' /etc/passwd

匹配/etc/passwd中包含root或nologin的全部行。awk '/root/ || /nologin/{print $0}' /etc/passwd

匹配/etc/passwd中第3個字段包含小於50而且第4個字段大於60而且第7行包含/sbin/nologin的全部行
    awk 'BEGIN{FS=":"}$3>50 && $4<60 && $7~/\/sbin\/nologin/{printf "%s %s %s\n",$3,$4,$7}' /etc/passwd

11.4 動做表達式中的算術運算符

+
-
*
\
^或**    乘方
++x
x++
--x
x--
例:
awk 'BEGIN{var1=10;var2="hello";print var1,var2}'
awk 'BEGIN{num1=10;num2+=num1;print num1,num2}'
awk 'BEGIN{num1=10;num2=29;print num1+num2}'
awk 'BEGIN{num1=10;num2=29;print num1-num2}'
awk 'BEGIN{num1=10;num2=29;print num1*num2}'
awk 'BEGIN{num1=10;num2=29;print num1/num2}'
awk 'BEGIN{num1=10;num2=29;print num1^num2}'
awk 'BEGIN{x=10;y=20;print x++;y++}'
awk 'BEGIN{x=10;y=20;print ++x;++y}'
awk 'BEGIN{num1=10;num2=29;printf "%0.2f\n",num1/num2}' #保留兩位小數
例:使用awk計算某文件中空白行的數量
awk '/^$/{sum++}END{print sum}' my.cnf
例:計算課程分數平均值
Allen     90 99 93 73
Jone     83 23 38 97
Monica     99 77 89 43
Jerry     77 44 32 91

awk 'BEGIN{printf "%-8s %-8s %-8s %-8s %-8s\n","姓名","語文","數學","物理","平均分"}{total=$2+$3+$4+$5;avg=total/4;printf "%-8s %-8d %-8d %-8d %-8d %0.2f\n",$1,$2,$3,$4,$5,avg}' score.txt

11.5 條件

if (條件表達式1)
    動做1
else if (條件表達式2)
    動做2
else
    動做3
例:
awk 'BEGIN{FS=":"}{if($3<50) {printf "%-10s %-4d\n","小於50的uid",$3} else if($3<80) {printf "%-10s %-4d\n","小於80的uid",$3} else {printf "%-10s %-4d\n","其它uid",$3}}' /etc/passwd

awk的代碼可能很長,這個時候能夠寫成腳本用-f來調用web

BEGIN {
    FS=":"
}

{
    if($3<50) {
        printf "%-10s %-4d\n","小於50的uid",$3
    } else if($3<80) {
        printf "%-10s %-4d\n","小於80的uid",$3
    } else {
        printf "%-10s %-4d\n","其它uid",$3
    }
}

awk -f script.awk /etc/passwd
例:計算課程分數平均值,而且只打印分數大於70的同窗的姓名和分數
Allen     90 99 93 73
Jone     83 23 38 97
Monica     99 77 89 43
Jerry     77 44 32 91

awk '{total=$2+$3+$4+$5;avg=total/4;if(avg>70){printf "%-10s %-0.2f\n",$1,avg}}' score.txt

11.6 循環

while(條件表達式)
    動做

do
    動做
while(條件表達式)

for(初始化計數器;測試計數器;計數器變動)
    動做
例:計算1+2+3+...+100的和,分別使用do-while、while、for實現
awk 'BEGIN{for(i=1;i<=100;i++){sum+=i};printf "sum=%d\n",sum}'
awk 'BEGIN{do{sum+=i++}while(i<=100);printf "sum=%d\n",sum}'
awk 'BEGIN{while(i<=100){sum+=i++};printf "sum=%d\n",sum}'

11.7 字符串函數

函數名                   解釋         函數返回值
-----------------------------------------------------------------------------------------------------------
length(str)            計算字符串長度                                                 整數返回值
index(str1,str2)         在str1中查找str2的位置                                         返回值爲索引,從1開始
toupper(str)             轉換爲大寫                                                     轉換後的大寫字符串
tolower(str)             轉換爲小寫                                                     轉換後的小寫字符串
substr(str,m,n)         從str的m個字符截取n位                                             截取後的子串
split(str,arr,fs)         按fs切割字符串,結果保存到arr(分隔符默認是空格,能夠省略)         切割後的子串的個數
match(str,RE)             在str中按照RE查找,返回位置                                     返回索引位置,從1開始

sub(RE,RepStr,str)        在str中按RE搜索字符串並將其替換爲RepStr,只替換第一個,返回替換的個數
gsub(RE,RepStr,str)        在str中按RE搜索字符串並將其替換爲RepStr,替換全部
例:
awk 'BEGIN{print length("abcd")}'
awk 'BEGIN{print index("abcd","c")}'
awk 'BEGIN{print toupper("abCd")}'
awk 'BEGIN{print tolower("abCd")}'

awk 'BEGIN{print substr("hello,world",3,6)}'
awk 'BEGIN{print split("root:x:0:0:root",arr,":");print arr}'
awk 'BEGIN{print match("hello,world", /lo/)}'
例:返回/etc/passwd中每一個字段的長度
awk 'BEGIN{FS=":";OFS=":"}{print length($1),length($2),length($3),length($4),length($5),length($6),length($7)}' /etc/passwd

搜索"i have a dream"中ea的位置
awk 'BEGIN{print index("i have a dream","ea")}'
awk 'BEGIN{print match("i have a dream","ea")}'

將"Hadoop is a bigdata framework"轉換爲小寫
awk 'BEGIN{print tolower("Hadoop is a bigdata framework")}'

將"Hadoop is a bigdata framework"轉換爲大寫
awk 'BEGIN{print toupper("Hadoop is a bigdata framework")}'

將"Hadoop is a bigdata framework"按空格分割後保存在數組中
awk 'BEGIN{str="Hadoop is a bigdata framework";split(str,arr," ");for(a in arr){print arr[a]}}'

找出字符串"Transaction 23345 start: select * from master"中第一個數字出現的位置

awk 'BEGIN{str="Transaction 23345 start: select * from master";print match(str,/[0-9]/)}'

截取字符串"Transaction 23345 start: select * from master",從第4個開始截取5位
awk 'BEGIN{str="Transaction 23345 start: select * from master";print substr(str,4,5)}'

替換"Transaction 23345 start, Event ID: 9002"中出現的第一個數字串爲$
awk 'BEGIN{str="Transaction 23345 start, Event ID: 9002";count=sub(/[0-9]+/,"$",str);print count,str}'

11.8 選項

-v     參數傳遞
-f     指定awk腳本文件
-F     指定分隔符,能夠連着寫
-V     查看awk版本
例:
awk -v arg1=12 -v arg2="hello world" 'BEGIN{print arg1,arg2}'
awk -F ":" '{print $1}' /etc/passwd
awk -F: '{print $1}' /etc/passwd

11.9 awk中數組的用法

  • 數組使用(索引從0開始)
array=("janee" "jone" "jacek" "jordan")
打印元素             echo ${array[0]}、echo ${array[@]}
打印元素個數         echo ${#array[@]}
打印元素長度         echo ${#array[0]}
給元素賦值        array[2]="messi"
刪除元素            unset array[2]、unset array
分片訪問            echo ${array[0]:1:3}
元素替換            ${array[@]/e/E}(替換元素中的第一個e爲E)、${array[@]//e/E}(替換元素中的全部e爲E)
元素便利            for a in ${array[@]}; do echo $a; done
  • awk中數組的用法(索引從1開始)
awk 'BEGIN{str="hadoop spark yarn storm flume";split(str,array," ");for(i=1;i<=length(array);i++){print array[i]}}'

awk的數組中可使用字符串做爲數組的下標
awk 'BEGIN{array["var1"]="zhangsan";array["var2"]="lisi";array["var3"]="wangwu";for(i in array){print array[i]}}'
例:統計各類tcp狀態鏈接狀態數
netstat -an | grep tcp | awk '{array[$6]++}END{for(i in array){print i,array[i]}}'
例:計算縱向橫向總和
Allen     90 99 93 73
Jone     83 23 38 97
Monica     99 77 89 43
Jerry     77 44 32 91

awk '{line++;line_sum=0;for(i=1;i<=NF;i++){line_sum+=$i;col_sum[i]+=$i;printf "%-6s ",$i};print line_sum}END{printf "%-6s","";for(i=2;i<=length(col_sum);i++){printf "%-6s ",col_sum[i]};printf "\n"}' score.txt

輸出:
Allen   90     99     93     73     355
Jone    83     23     38     97     241
Monica  99     77     89     43     308
Jerry   77     44     32     91     244
       349    243    252    304

11.10 awk中數組的用法

例:用awk腳本處理數據並生成報告
生成數據的腳本:insert.sh

#!/bin/bash
function create_random {
    min=$1
    max=$(($2-$min+1))
    num=$(date +%s%N)
    echo $(($num%$max+$min))
}

INDEX=1
while true
do
    for user in Mike Allen Jerry Tracy Hanmeimei Lilei
    do
        COUNT=$RANDOM
        NUM1=`create_random 1 $COUNT`
        NUM2=`expr $COUNT - $NUM1`
        echo "`date "+%Y-%m-%d %H:%M:%S"`" $INDEX Batches: $user insert $COUNT data into table 'test1', insert $NUM1 records successfully, failed insert $NUM2 records >> /root/script/data.txt
        INDEX=`expr $INDEX + 1`
    done
done

數據格式:
2019-04-17 23:44:36 495 Batches: Jerry insert 7658 data into table test1, insert 1008 records successfully, failed insert 6650 records
2019-04-17 23:44:36 496 Batches: Tracy insert 17609 data into table test1, insert 10348 records successfully, failed insert 7261 records
2019-04-17 23:44:36 497 Batches: Hanmeimei insert 14256 data into table test1, insert 1599 records successfully, failed insert 12657 records
2019-04-17 23:44:36 498 Batches: Lilei insert 9279 data into table test1, insert 7856 records successfully, failed insert 1423 records
2019-04-17 23:44:36 499 Batches: Mike insert 22652 data into table test1, insert 6291 records successfully, failed insert 16361 records

(1)、統計每一個人員插入了多少條數據進數據庫
awk 'BEGIN{printf "%-10s %-10s\n","name","total"}{stat[$5]+=$7}END{for(i in stat){printf "%-10s %-10s\n",i,stat[i]}}' data.txt

(2)、統計每一個人員插入成功和失敗了多少條數據進數據庫
awk 'BEGIN{printf "%-10s %-10s %-10s %-10s\n","User","Total","Succeed","Failed"}{sum[$5]+=$7;suc_sum[$5]+=$13;fail_sum[$5]+=$18}END{for(i in sum){printf "%-10s %-10s %-10s %-10s\n",i,sum[i],suc_sum[i],fail_sum[i]}}' data.txt

(3)、在(2)的基礎上統計所有插入記錄數
awk 'BEGIN{printf "%-10s %-10s %-10s %-10s\n","User","Total","Succeed","Failed"}{sum[$5]+=$7;suc_sum[$5]+=$13;fail_sum[$5]+=$18}END{for(i in sum){all_sum+=sum[i];all_suc_sum+=suc_sum[i];all_fail_sum+=fail_sum[i];printf "%-10s %-10s %-10s %-10s\n",i,sum[i],suc_sum[i],fail_sum[i]};printf "%-10s %-10s %-10s %-10s\n","",all_sum,all_suc_sum,all_fail_sum}' data.txt

(4)、查找丟失數據,也就是成功+失敗的記錄數不等於總共插入的記錄數
awk '{if($7!=$13+$18){print $0}}' data.txt

12. mysql操做

12.1 安裝啓動mariadb

yum install mariadb mariadb-server mariadb-libs -y
systemctl start mariadb

13. 腳本工具

腳本工具功能概述
(1)、實現一個腳本,該腳本提供相似supervisor的功能,能夠對進程進行管理
(2)、一鍵查看全部進程運行狀態
(3)、單個或批量啓停進程
(4)、提供進程分組功能,能夠按組查看進程運行狀態,能夠按組啓停進程
配置文件 process.cfg

[GROUP_LISE]
WEB_LIST
DB_LIST
HADOOP_LIST
YARN_LIST

[WEB_LIST]
nginx
httpd

[DB_LIST]
mysql
postgresql

[HADOOP_LIST]
datanode
namenode

[YARN_LIST]
resourcemanager
nodemanager

[nginx]
description="Web Server 1"
program_name=tail
parameter=-f /root/tmp/web-nginx.conf


[httpd]
description="Web Server 2"
program_name=tail
parameter=-f /root/tmp/web-httpd.conf

[mysql]
description="High Perfrmance Database"
program_name=tail
parameter=-f /root/tmp/db-mysql.conf

[postgresql]
description="High Perfrmance Database"
program_name=tail
parameter=-f /root/tmp/db-postgresql.conf

[datanode]
description="Hadoop datanode"
program_name=tail
parameter=-f /root/tmp/hadoop-datanode.conf

[namenode]
description="Hadoop namenode"
program_name=tail
parameter=-f /root/tmp/hadoop-namenode.conf

[resourcemanager]
description="yarn resourcemanager"
program_name=tail
parameter=-f /root/tmp/yarn-resourcemanager.conf

[nodemanager]
description="yarn nodemanager"
program_name=tail
parameter=-f /root/tmp/yarn-nodemanager.conf
#!/bin/bash

THIS_PID=$$
GROUP_LIST=GROUP_LIST
CFG_FILE=/root/script/tmp/process.cfg

function group_list {
        group_list=`sed -n "/\[$GROUP_LIST\]/,/^\[.*\]/p" $CFG_FILE | grep -v "^$" | grep -v "\[.*\]" | grep -v "\#"`
        echo $group_list
}

function get_all_process {
        for group in $(group_list)
        do
                p_list=$(get_all_process_by_group $group)
                echo $p_list
        done
}

function get_all_process_by_group {
        group_process=`sed -n "/\[$1\]/,/\[.*\]/p" $CFG_FILE | grep -v "^$" | grep -v "\[.*\]" | grep -v "\#"`
        echo $group_process
}

function is_group_exists {
        count=`sed -n "/\[$1\]/p" $CFG_FILE | grep -v "$GROUP_LIST" | wc -l`
        if [ $count -eq 1 ]; then
                return 0
        else
                return 1
        fi
}

function get_group_by_process_name {
        for g in $(group_list)
        do
                for p in `get_all_process_by_group $g`
                do
                        if [ $p == $1 ]; then
                                echo "$g"
                        fi
                done
        done
}

function get_process_info_by_pid {
        ps -ef | awk -v pid=$1 '$2==pid{print}' &> /dev/null
        if [ $? -eq 0 ]; then
                proc_status="RUNNING"
        else
                proc_status="STOPPED"
        fi

        proc_cpu=`ps aux | awk -v pid=$1 '$2==pid{print $3}'`
        proc_mem=`ps aux | awk -v pid=$1 '$2==pid{print $4}'`
        proc_start_time=`ps -p $1 -o lstart | grep -v "STARTED"`
}

function get_pid_by_process_name {
        if [ $# -ne 1 ]; then
                return 1
        else
                pid=`ps -ef | grep "$1" | grep -v grep | grep -v "$0" |  awk '{print $2}'`
                echo $pid
        fi
}

function format_print {
        group=`get_group_by_process_name $1`
        ps -ef | grep $1 | grep -v grep | grep -v $THIS_PID &> /dev/null
        if [ $? -eq 0 ]; then
            for pids in `get_pid_by_process_name $1`
            do
                for _pid in $pids
                do
                    get_process_info_by_pid $_pid

                    awk -v p_name="$1" \
                    -v p_group="$group" \
                    -v p_id="$_pid" \
                    -v p_status="$proc_status" \
                    -v p_cpu="$proc_cpu" \
                    -v p_mem="$proc_mem" \
                    -v p_start_time="$proc_start_time" \
                    'BEGIN{printf "%-20s%-10s%-10s%-10s%-10s%-10s%-10s\n",p_name,p_group,p_status,p_id,p_cpu,p_mem,p_start_time;}'
                done
            done
        else
                    awk -v p_name="$1" \
                    -v p_group="$group" \
                    'BEGIN{printf "%-20s%-10s%-10s%-10s%-10s%-10s%-10s\n",p_name,p_group,"NULL","NULL","NULL","NULL","NULL";}'
        fi
}

echo "********************************************************************************************************"
echo `group_list`

echo `get_all_process`

echo `get_all_process_by_group DB_LIST`

echo `is_group_exists WEB_LIST`

echo $(get_group_by_process_name mariadb)

format_print $1
echo "********************************************************************************************************"

14. 其它

ps -ef | grep nginx | awk '{print $2}' | xargs kill

$?        命令執行的結果,0表示成功,其它表示有異常
$$        腳本執行的子進程的pid
$#         參數數量
$0      shell文件名
$@      shell執行的時候傳入的全部參數
shift    shell執行的時候跳過一個傳入的參數
netstat
    -l[listening]
    -a[all]
    -t[tcp]
    -p[program] Show the PID and name of the program to which each socket belongs.
相關文章
相關標籤/搜索