https://www.cnblogs.com/zhangcaiwang1/p/9607622.html
1.特殊变量------------------------------------------------------------------
$0 脚本自身名字
$? 判断执行是否成功 0为成功 非0为失败
$# 位置参数总数
$* 所以位置参数被看做一个字符串
$@ 每个位置参数被看做独立字符串
$$ 显示当前的pid
$! 上一条执行后台进程的PID
2.shell字符串处理${}
1.1 获取字符串长度
A='zhangcaiwang'
echo $A
取长度: echo ${#A}
1.2 字符串切片
A='zhangcaiwang'
echo ${A:0:5} #0:5 取值空间
echo ${A:6:2} #取6个字符串后两个
echo ${A:(-1)} #截取最后一个字符串
echo ${A:(-3):2} #截取后三个字符串的两个字符
1.3 替换字符串 格式${parameter/pattern/string}
A='zhang cai wang'
echo ${A/cai/wang}
全部替换 echo ${A//cai/wang}
正则匹配字符串
var=123abc
echo ${var//[^0-9]/}
echo ${var//[0-9]/}
1.4字符串截取 #去掉左边 最短匹配模式 ##最长匹配模式 %去掉右边 最短匹配模式 %%最长匹配模式
URL="http://www.baidu.com/user/a.html"
以//为分隔符截取右边字符串:
echo ${URL#*//} #以//为分隔符 获取最右边字符串
www.baidu.com/user/a.html
以/为分隔符截取右边字符串:
echo ${URL##*/}
a.html
以//为分隔符截取左边字符串:
echo ${URL%%//*}
http:
以/为分隔符截取左边字符串:
echo ${URL%/*}
http://www.baidu.com/user
1.5 字体颜色
echo -e " 33[31m Hello world! 33[0m" 红色
30:黑
31:红
32:绿
33:黄
34:蓝色
35:紫色
36:深绿
37:白色
40:黑
41:深红
42:绿
43:黄色
44:蓝色
45:紫色
46:深绿
47:白色
3.shell条件表达式 ------------------------------------------------------------------
[ expression ] 示例 [ 1 -eq 1 ]
[[ expression ]] 示例 [[ 1 -eq 1 ]]
test expression 示例 test 1 -eq 1 等同于[]
3.1 整数比较
-eq 等于 示例 [ 1 -eq 1 ] 为true
-ne 不等于 示例 [ 1 -ne 1 ] 为false
-gt 大于 示例 [ 2 -gt 1 ] 为true
-lt 小于 示例 [ 2 -lt 1 ] 为false
-ge 大于等于 示例 [ 2 -ge 1 ] 为true
-le 小于等于 示例 [ 2 -le 1 ] false
3.2 字符串比较
== 等于 示例 [ "a" == "a" ] 为true
!= 不等于 示例 [ "a" != "a" ] 为false
-n 字符串长度不等于0为真 示例 A=1 B="" [ -n "$A" ] 为true [ -n "$B" ] 为false
-z 字符串长度等于0为真 示例 A=1 B="" [ -z "$A" ] 为false [ -z "$B" ] 为true
str 字符串存在为真 示例 A=1 B="" [ $A ] 为true [ $B ] 为false
************使用-z 或-n 判断字符串长度时,变量要加双引号****
A="" B=1
[ -z "$A" ] && echo yes || echo no #如果$A 值为空 输出 yes 否则输入no
[ -n "$B" ] && echo yes || echo no #如果$B 有值 输出yes 否则输入no
使用双中括号就不用引号
[[ -z $A ]] && echo yes || echo no #空为真 不空为假
[[ -n $B ]] && echo yes || echo no #不空为真 非空位为假
3.3 文件测试
-e 文件或目录存在 [ -e path ] path 存在为true
-f 文件存在为真 [ -f file_path ] 文件存在为true
-d 目录存在为真 [ -d dir_path ] 目录存在为true
-r 有读权限为真 [ -r file_path ] file_path 有读权限为 true
-w 有写权限为真 [ -w file_path ] file_path 有写权限为 true
-x 有执行权限为真 [ -x file_path ] file_path 有执行权限为 true
3.4 布尔运算符
!非关系 条件结果取反 示例 [ ! 1 -eq 2 ]为 true
-a 和关系,在[]表达式中使用 [ 1 -eq 1 -a 2 -eq 2 ]为 true
-o 或关系,在[]表达式中使用 [ 1 -eq 1 -o 2 -eq 1 ]为
3.5 逻辑判断符
&& 逻辑和,在[[]]和(())表达式中或判断表达式是否为真时使用
示例
[[ 1 -eq 1 && 2 -eq 2 ]]为 true
(( 1 == 1 && 2 == 2 ))为 true
[ 1 -eq 1 ] && echo yes 如果&&前面表达式为 true 则执行后面的
|| 逻辑或,在[[]]和(())表达式中或判断表达式是否为真时使用
[[ 1 -eq 1 || 2 -eq 1 ]]为 true
(( 1 == 1 || 2 == 2 ))为 true
[ 1 -eq 2 ] || echo yes 如果||前面表达式为 false 则执行后面的
3.6 数学运算 + 加 - 减 *乘 /除 % 取余
运算表达式 $(()) 示例 $((1+1)) $[] 示例 $[1+1]
复杂运算 let 赋值并运算,支持++、 -- 示例 let VAR=(1+2)*3 ; echo $VAR
expr 乘法*需要加反斜杠转义* 示例 expr 1 * 2 运算符两边必须有空格
bc 计算器 示例 echo 'scale=2;10/3' |bc 用 scale 保留两位小数点
4.shell括号总结------------------------------------------------------------------
( ) 用途 1:在运算中,先计算小括号里面的内容 用途 2:数组 用途 3:匹配分组
(( )) 用途 1:表达式,不支持-eq 这类的运算符。不支持-a 和-o,支持<=、 >=、 <、 >这类比较符和&&、 ||
用途 2: C 语言风格的 for(())表达式
$( ) 执行 Shell 命令,与反撇号等效
$(( )) 用途 1:简单算数运算 用途 2:支持三目运算符 $(( 表达式?数字:数字 ))
[ ] 条件表达式,里面不支持逻辑判断符
[[ ]] 条件表达式,里面不支持-a 和-o,不支持<=和>=比较符,支持-eq、 <、 >这类比较符。支持=~模式匹配,也可以不用双引号也不会影响原意,比[]更加通用
$[ ] 简单算数运算
{ } 对逗号(,)和点点(...)起作用,比如 touch {1,2}创建 1 和 2 文件, touch{1..3}创建 1、 2 和 3 文件
${ } 用途 1:引用变量 用途 2:字符串处理
5.shell流程控制------------------------------------------------------------------
5.1 if 语句
单分支
if 条件表达式; then
命令
fi
示例
#!/bin/bash A=10 if [ $A -gt 5 ];then echo yes fi
双分支
if 条件表达式; then
命令
else
命令
fi
示例1:
A=10
if [ $A -lt 5 ];then echo yes else echo no fi
示例2:
判断nginx进程是否在运行
#!/bin/bash NAME=nginx NUM=$(ps -ef | grep nginx | grep -vc grep) if [ $NUM -gt 1 ];then echo "$NAME running" else echo "$NAME no running" fi
多分支
if 条件表达式; then
命令
elif 条件表达式; then
命令
else
命令
fi
示例 1:
#!/bin/bash N=$1 if [ $N -eq 3 ]; then echo "eq 3" elif [ $N -eq 5 ]; then echo "eq 5" elif [ $N -eq 8 ]; then echo "eq 8" else echo "no" fi
示例2:
#!/bin/bash if [ -e /etc/redhat-release ]; then yum install wget -y elif [ $(cat /etc/issue |cut -d' ' -f1) == "Ubuntu" ]; then apt-get install wget -y else Operating system does not support. exit fi
5.2 for 循环
for 变量名 in 取值列表; do
命令
done
示例1:
#!/bin/bash for i in {1..3}; do echo $i done
示例2:
#!/bin/bash for i in "$@"; { # $@是将位置参数作为单个来处理 echo $i }
默认for 循环的取值列表是以空白符分隔系统变量里的$IFS,如果想指定分隔符,可以重新赋值$IFS 变量:
#!/bin/bash OLD_IFS=$IFS IFS=":" for i in $(head -1 /etc/passwd); do echo $i done IFS=$OLD_IFS # 恢复默认值
for 循环c语言写法:
for (( expr1 ; expr2 ; expr3 )) ; do list ; done
示例3:
#!/bin/bash for ((i=1;i<=5;i++)); do # 也可以 i-- echo $i done
示例4:检查多个域名是否可以访问
#!/bin/bash URL="www.baidu.com www.sina.com www.jd.com" for url in $URL; do HTTP_CODE=$(curl -o /dev/null -s -w %{http_code} http://$url) if [ $HTTP_CODE -eq 200 -o $HTTP_CODE -eq 301 ]; then echo "$url OK." else echo "$url NO!" fi done
5.3 while 语句
while 条件表达式; do
命令
done
示例1:
#!/bin/bash N=0 while [ $N -lt 5 ]; dolet N++ echo $N done
示例2: 逐行读文件
#!/bin/bash cat ./a.txt | while read LINE; do echo $LINE done
或
#!/bin/bash while read LINE; do echo $LINE done < ./a.txt
或
#!/bin/bash exec < ./a.txt # 读取文件作为标准输出 while read LINE; do echo $LINE done
break 是终止循环
#!/bin/bash N=0 while true; do let N++ if [ $N -eq 5 ]; then break fi echo $N done
continue 是跳出当前循环
#!/bin/bash N=0 while [ $N -lt 5 ]; do let N++ if [ $N -eq 3 ]; then continue fi echo $N done
5.4 case语句
case 模式名 in
模式 1)
命令
;;
模式 2)
命令
;;
*)
不符合以上模式执行的命令
esac
示例3:
#!/bin/bash case $1 in start) echo "start." ;; stop) echo "stop." ;; restart) echo "restart." ;; *) echo "Usage: $0 {start|stop|restart}" esac
示例4:
#!/bin/bash case $1 in [0-9]) echo "match number." ;; [a-z]) echo "match letter." ;; '-h'|'--help') echo "help" ;; *) echo "Input error!" exit esac
5.5 select 语句类似for循环语句
select 变量 in 选项 1 选项 2; do
break
done
#!/bin/bash PS3="Select a number: " while true; do select mysql_version in 5.1 5.6 quit; do case $mysql_version in 5.1) echo "mysql 5.1" break ;; 5.6) echo "mysql 5.6" break ;; quit) exit ;; *) echo "Input error, Please enter again!" break esac done done
6.shel函数与数组
格式:
func(){
command
}
示例1:函数返回值
#!/bin/bash func() { VAR=$((1+1)) return $VAR echo "This is a function." } func echo $?
示例2:通过 Shell 位置参数给函数传参
#!/bin/bash func() { echo "Hello $1" } func world
7.数组 array=(元素 1 元素 2 元素 3 ...)
定义方法 1:初始化数组
获取所有元素
array=a b c echo ${array[*]} # *和@ 都是代表所有元素 array=(a b c)
定义方法 2:新建数组并添加元素
array[下标]=元素
获取元素下标:
a=(1 2 3) echo ${!a[@]}
获取数组长度:
a=(1 2 3 4 5 6 7 8) echo ${#array[*]}
获取第一个元素:
echo ${array[0]}
获取第二个元素:
echo ${array[1]}
获取第三个元素:
echo ${array[2]}
添加元素:
array=(1 2 3) array[3]=d echo ${array[*]} a b c d
添加多个元素:
array+=(e f g) echo ${array[*]} a b c d e f g
删除第一个元素:
unset array[0] # 删除会保留元素下标 echo ${array[*]} b c d e f g
删除数组:
unset array
示例1:
#!/bin/bash for i in $(seq 1 10); do array[a]=$i let a++ done echo ${array[*]}
示例2:
#/bin/bash IP=(192.168.1.1 192.168.1.2 192.168.1.3) for ((i=0;i<${#IP[*]};i++)); do echo ${IP[$i]} done
7.shell 正则表达式------------------------------------------------------------------
基础正则表达式: BRE(basic regular express)
扩展正则表达式: ERE(extend regular express),扩展的表达式有+、 ?、 |和()
. 匹配除换行符(
)之外的任意单个字符 示例 匹配 123:
echo -e "123 456" |grep '1.3'
^ 匹配前面字符串开头 示例 匹配以 abc 开头的行:
echo -e "abc xyz" |grep ^abc
$ 匹配前面字符串结尾 示例 匹配以 xyz 结尾的行:
echo -e "abc xyz" |grep xyz$
* 匹配前面一个字符零个或多个 匹配x,xo和xoo:
echo -e "x xo xoo o oo" | grep "xo*" x 是必须的,批量了0零个或多个
+ 匹配前面字符1个或多个 匹配 abc 和 abcc:
echo -e "abc abcc add" |grep -E 'ab+'
匹配单个数字:
echo "113" |grep -o '[0-9]'
连续匹配多个数字:
echo "113" |grep -E -o '[0-9]+
? 匹配前面字符0个或 1个 匹配 ab或abc:
echo -e "ac abc add" | grep -E 'a?c'
[] 匹配中括号之中的任意一个字符 匹配a或c:
echo -e "a b c" | grep '[ac]'
[.-.] 匹配中括号范围内的任意一个字符 匹配所有字母:
echo -e "a b c" |grep '[a-z]'
[^] 匹配[^字符] 之外的任意一个字符 匹配a或b:
echo -e "a b c" | grep '[^c-z]'
^[^] 匹配不是中括号内任意一个字符开头的行 匹配不是#开头的行:
grep '^[^#]' /etc/http/conf/httpd.conf
{n}或{n,} 匹配花括号前面字符最少n个字符 匹配abc字符串(至少三个字符以上字符串)
echo -e "a abc c" |grep -E '[a-z]{3}'
{n,m} 匹配花括号前面字符至少n个字符 最多m个字符 匹配12和123
echo -e "1 12 123 1234" | grep -E -w -o '[0-9]{2,3}'
< 边界符 匹配字符串开始 匹配开始是123和1234
echo -e "1 12 123 1234" |grep '<123'
> 边界符 匹配字符串结束 匹配结束是1234
echo -e "1 12 123 1234" | grep '4>'
() 小括号里面作为一个组合 匹配123a字符串
echo "123abc" |grep -E -o '([o-9a-z]){4}'
| 匹配竖杠两边的任意一个 匹配12和123
echo -e "1 12 123 1234" | grep -E '12>|123>'
转义符 匹配 1.2
8.shell文本处理三剑客------------------------------------------------------------------
grep
-E 扩展正则表达式
-P perl正则表达式
-e 使用模式匹配 可指定多个模式匹配
-f 从文件的每一行获取匹配模式
-i 忽略大小写
-w 模式匹配整个单词
-x 模式匹配整行
-v 打印不匹配的行
-m 输出匹配的结果num数
-n 打印行号
-H 打印每个匹配的文件名
-h 不输出文件名
-o 只打印匹配的内容
-q 不输出正常信息
-s 不输出错误信息
-r 递归目录
-c 只打印每个文件匹配的行数
-B 打印匹配的前几行
-A 打印匹配的后几行
-C 打印匹配的前后几行
--color 匹配的字体颜色
1)输出b文件中在a文件相同的行
grep -f a b
2)输出b文件中在a文件不同的行
grep -v -f a b
3)匹配多个模式
echo "a bc de" | xargs -n1 | grep -e 'a' -e 'bc' #xargs -n1 打印竖着排列
4)去除空格http.conf文件空行或开头#号的行
grep -E -v "^$|^#" /etc/http/conf/httpd.conf
5)匹配开头不分大小写的单词
echo "A a b c" | xargs -n1 | grep '[Aa]'
6)只显示匹配的字符串
echo "this is a test" |grep -o 'is'
7)输出匹配的前五个结果
seq 1 20 | grep -m 5 -E '[0-9]{2}'
8)统计匹配多少行
seq 1 20 |grep -c -E '[0-9]{2}'
9)匹配b字符开头的行
echo "a bc de" | xargs -n1 |grep '^b'
10)匹配de字符结尾的行并输出匹配的行
echo "a ab abc abcd abcde" | xargs -n1 | grep -n 'de$'
11)递归搜索/etc/目录下包含ip的conf后缀文件
grep -r '192.168.1.1' /etc --include *.
12)排除搜索bak后缀的文件
grep -r '192.168.1.1' /opt --exclude *.bak
13)排除来自file中的文件
grep -r '192.168.1.1' /opt --exclude-from file
14)匹配41或42的数字
seq 41 45 | grep -E '4[12]'
15)匹配至少2个字符
seq 13 | grep -E '[0-9]{2}'
16)匹配至少2个字符的单词 最多3个字符的单词
echo "a ab abc abcd abcde" |xargs -n1 |grep -E -w -o '[a-z]{2,3}'
17)匹配所有ip
ifconfig |grep -E -o "[0-9]{1,3}.[0-9]{1,3}.[0-9]{1,3}.[0-9]{1,3}"
18)打印5后3行
seq 1 10 | grep 5 -A 3
19)打印匹配结果及前3行
seq 1 10 | grep 5 -B 3
20)打印匹配结果及前后3行
seq 1 10 | grep 5 -C 3
21) 不显示输出
grep -s 'a' abc 不显示错误输出 grep -q 'a' a.txt 不显示正常输出
sed ------------------------------------------------------------------
-n 不打印模式
-e 执行脚本 表达式来处理
-f 执行动作从文件读取执行
-i 修改原文件
-r 使用扩展正则
s/regexp/replacement/ 替换字符串
p 打印当前模式空间
P 打印模式空间的第一行
d 删除模式空间 开始下个一个循环
D 删除模式空间的第一行 开始下一个循环
= 打印当前行号
a ext 当前行追加文本
i ext 当前行上面插入文本
c ext 所选行替新文本
q 退出sed脚本
r 追加文本来自文件
:label label为b 和t 命令
b label 分支到脚本中带有标签的位置
t label 如果s/// 是一个成功的替换 才跳转到标签
h H 复制/追加模式空间到保持空间
g G 复制/追加保持空间到模式空间
x 交换模式空间和保持空间
l 打印模式空间的行 并显示控制字符$
n N 读取/追加下一行输入到模式空间
w filename 写入当前模式空间到文件
! 取反 否定
& 引用已匹配字符串
first^step 步长 每step行 从first开始
$ 匹配最后一行
/regexp/ 正则表达式匹配行
number 只匹配指定行
addr1 addr2 开始匹配addr1 行开始 直接addr2 行结束
addr1 ~N 从addr1行开始 到N行结束
借助文本tail /etc/services演示
3gpp-cbsp 48049/tcp # 3GPP Cell Broadcast Service Protocol
isnetserv 48128/tcp # Image Systems Network Services
isnetserv 48128/udp # Image Systems Network Services
blp5 48129/tcp # Bloomberg locator
blp5 48129/udp # Bloomberg locator
com-bardac-dw 48556/tcp # com-bardac-dw
com-bardac-dw 48556/udp # com-bardac-dw
iqobject 48619/tcp # iqobject
iqobject 48619/udp # iqobject
matahari 49000/tcp # Matahari Broker
匹配打印(p)------------------------------------------------------------------
1)打印匹配blp5开头的行 tail /etc/services | sed -n '/^blp5/p' 2)打印第一行 tail /etc/services | sed -n '1p' 3)打印第一行至第三行 tail /etc/services | sed -n '1,3p' 4)打印奇数行 seq 10 | sed -n '1~2p' 5)打印匹配行及后一行 tail /etc/services | sed -n '/blp5/,+1p' 6)打印最后一行 tail /etc/services | sed -n '$p' 7)不打印最后一行 tail /etc/services | sed -n '$!p' 8)匹配范围 tail /etc/services | sed -n '/^blp5/,/^com/p' 9)匹配开头行到最后一行: tail /etc/services | sed -n '/blp5/,$p' 10)引用变量取行 a=1 tail /etc/services | sed -n "$a,3p" 11)匹配删除 tail /etc/services | sed '/blp5/d' 12)删除第一行 tail /etc/services |sed '1d' 13)删除1和2行 tail /etc/services | sed '1~2d' 14)删除1至3行 tail /etc/services |sed '1,3d' 15)替换字符串 全局替换加g s'/blp5/test/g' tail /etc/services |sed 's/blp5/test/' 16)替换开头是blp5的字符串并打印 tail /etc/services | sed -n 's/blp5/test/p' 17)使用&命令引用匹配内容并替换 tail /etc/services |sed 's/48049/&.0/' 18) ip加引号 echo '10.10.10.1 10.10.10.2 10.10.10.3' |sed -r 's/[^ ]+/"&"/g 19)对1-4行的blp5进行替换 tail /etc/services | sed '1,4s/blp5/test/' 20)对匹配行进行替换 tail /etc/services | sed '/48129/tcp/s/blp5/test/' 21)二次匹配替换 tail /etc/services | sed 's/blp5/test/;s/3g/4g/' 22)分组使用,在每个字符串后面添加 123 tail /etc/services |sed -r 's/(.*) (.*)(#.*)/12test 3/' #第一列是第一个小括号匹配,第二列第二个小括号匹配, 第三列一样。 将不变的字符串匹配分组, #通过数字按分组顺序反向引用 23)将协议与端口号位置调换 tail /etc/services |sed -r 's/(.*)(<[0-9]+>)/(tcp|udp)(.*)/13/24/' 24)替换 x 字符为大写: echo "abc cde xyz" |sed -r 's/(.*)x/1X/' 25)456 与 cde 调换: echo "abc:cde;123:456" |sed -r 's/([^:]+)(;.*:)([^:]+$)/321/' 26)注释匹配行后的多少行 seq 10 |sed '/5/,+3s/^/#/' 27)注释指定多行 seq 5 |sed -r '/^3|^4/s/^/#/' 28)去除开头和结尾空格或制表符 echo " 1 2 3 " |sed 's/^[ ]*//;s/[ ]*$//' 29)多重编辑-e tail /etc/services |sed -e '1,2d' -e 's/blp5/test/' 30)在 blp5 上一行添加 test tail /etc/services |sed '/blp5/i est' 31)在 blp5 下一行添加 test tail /etc/services |sed '/blp5/a est' 32)读取文件并追加到匹配行后(r) cat a.txt 456 tail /etc/services |sed '/blp5/r a.txt' 33)将匹配行写到文件(w) tail /etc/services |sed '/blp5/w b.txt' 34)获取总行数 seq 10 |sed -n '$=' 35)每三个数字加个一个逗号 echo "123456789" |sed -r 's/([0-9]+)([0-9]+{3})/1,2/'
awk------------------------------------------------------------------
-f 从文件中读取awk程序源文件
-F 指定fs为输入字段分隔符
-v 变量赋值
--posix 兼容postix正则表达式
--dump-variables 把awk命令是的全局变量写入文件 默认文件是awkvars.out
--profile 格式化awk语句到文件 默认是awkprof.out
BEGINP{} 给程序赋予初始状态 先执行的工作
END{} 程序结束之后执行的一些扫尾工作
/regular expression/ 为每个输入记录匹配正则表达式
parttern && pattern 逻辑and 满足两个模式
parttern || parttern 逻辑or 满足其中一个模式
! parttern 逻辑not 不满足模式
parttern1 parttern2 范围模式 匹配所有模式1的记录 直到匹配到模式2
FS 输入字段分隔符 默认是空格或制表符
OFS 输出字段分隔符 默认是空格
RS 输入记录分隔符 默认是换行符
NF 统计当前记录中字段个数
NR 统计记录编号,每处理一行记录,编号就会+1
ARGV 命令行参数数组序列数组,下标从 0 开始, ARGV[0]是 awk
ENVIRON 当前系统的环境变量
FILENAME 输出当前处理的文件名
(...) 分组
$ 字段引用
++ -- 递增 递减
+ - ! 加 减 逻辑否
* / % 乘 除 取余
|| & 管道
in 数组成员
&& || 逻辑and 逻辑or
= += -= *= /= %= ^= 变量赋值运算符
1.从文件读取 awk 程序处理文件
#cat <<EOF >test.awk '{print $2}' tail -n3 /etc/services | awk -f test.awk
2.指定分隔符,打印指定字段
tail -n3 /etc/services |awk '{print $2}'
3.指定冒号为分隔符打印第一字段:
awk -F ':' '{print $1}' /etc/passwd
4.多个分隔符,作为同一个分隔符处理
tail -n3 /etc/services |awk -F'[/#]' '{print $3}'
5.变量赋值
a=123 awk -v a=123 'BEGIN{print a}'
6.打印页眉
tail /etc/services |awk 'BEGIN{print "Service Port Description ==="}{print $0}'
7.打印页尾
tail /etc/services |awk '{print $0}END{print "====== ========"}'
8./re/正则匹配
匹配包含 tcp 的行:
tail /etc/services |awk '/tcp/{print $0}'
9.匹配开头是 blp5 的行:
tail /etc/services |awk '/^blp5/{print $0}'
10.匹配第一个字段是 8 个字符的行:
tail /etc/services |awk '/^[a-z0-9]{8} /{print $0}'
11.匹配记录中包含 blp5 和 tcp 的行:逻辑和 &&
tail /etc/services |awk '/blp5/ && /tcp/{print $0}'
12.匹配记录中包含 blp5 或 tcp 的行:逻辑或
tail /etc/services |awk '/blp5/ || /tcp/{print $0}'
13.不匹配开头是#和空行:
awk '! /^#/ && ! /^$/{print $0}' /etc/httpd/conf/httpd.conf
14.匹配范围
tail /etc/services |awk '/^blp5/,/^com/'
15.在程序开始前重新赋值 FS 变量,改变默认分隔符为冒号,与-F 一样。
awk 'BEGIN{FS=":"}{print $1,$2}' /etc/passwd |head -n5
16.OFS 默认以空格分隔,反向引用多个字段分隔的也是空格,如果想指定输出分隔符这样:
awk 'BEGIN{FS=":";OFS=":"}{print $1,$2}' /etc/passwd |head -n5
字符串拼接
awk 'BEGIN{FS=":"}{print $1"#"$2}' /etc/passwd |head -n5
18.RS 默认是 分隔每行,如果想指定以某个字符作为分隔符来处理记录
echo "www.baidu.com/user/test.html" |awk 'BEGIN{RS="/"}{print $0}'
19.替换某个字符:
tail -n2 /etc/services |awk 'BEGIN{RS="/";ORS="#"}{print $0}'
20.NF是字段的个数
echo "a b c d e f" |awk '{print NF}'
21.打印最后一个字段:
echo "a b c d e f" |awk '{print $NF}'
22.打印倒数第二个字段:
echo "a b c d e f" |awk '{print $(NF-1)}'
23.排除最后两个字段
echo "a b c d e f" |awk '{$NF="";$(NF-1)="";print $0}'
24.排除第一个字段:
echo "a b c d e f" |awk '{$1="";print $0}'
25.打印行数
tail -n5 /etc/services |awk '{print NR,$0}'
26.打印总行数:
tail -n5 /etc/services |awk 'END{print NR}'
27.打印第三行:
tail -n5 /etc/services |awk 'NR==3'
28.打印第三行第二个字段:
tail -n5 /etc/services |awk 'NR==3{print $2}'
29.打印前三行和行号:
tail -n5 /etc/services |awk 'NR<=3{print NR,$0
30.ENVIRON 调用系统变量
export a awk 'BEGIN{print ENVIRON["a"]}'
31.打印输出
awk 'BEGIN{n=0;if(n)print "true";else print "false"}'
32.截取整数
echo "123abc abc123 123abc123" |xargs -n1 | awk '{print +$0}'
33.打印奇数行
seq 6 |awk 'i=!i'
34.打印偶数行
seq 6 |awk '!(i=!i)'
35.不匹配某行
tail /etc/services |awk '!/blp5/{print $0}'
36.从小到大排序
seq 5 |shuf |awk '{print $0|"sort"}'
37.正则表达式匹配
seq 5 |awk '$0~3{print $0}' seq 5 |awk '$0~/[34]/{print $0}' seq 5 |awk '$0!~3{print $0}'
38.判断数组成员
awk 'BEGIN{a["a"]=123}END{if("a" in a)print "yes"}' </dev/null
39.求和
seq 5 |awk '{sum+=1}END{print sum}'
40.匹配数字字母的
echo "123abc#456cde 789aaa#aaabbb " |xargs -n1 |awk -F# '{if($2~/[0-9]/)print $2}'
41.双分支:
seq 5 |awk '{if($0==3)print $0;else print "no"}'
42.多分支:
awk '{if($1==4){print "1"} else if($2==5){print "2"} else if($3==6){print "3"} else {print "no"}}' file
43.遍历打印所有字段
awk '{i=1;while(i<=NF){print $i;i++}}' file awk '{for(i=1;i<=NF;i++)print $i}' file
44.for 语句遍历数组
seq -f "str%.g" 5 |awk '{a[NR]=$0}END{for(v in a)print v,a[v]}'
45.自定义数组
awk 'BEGIN{a[0]="test";print a[0]}'
46.通过 NR 设置记录下标 取值
tail -n3 /etc/passwd |awk -F: '{a[NR]=$1}END{print a[1]}'
47.通过 for 循环遍历数组
打印当前字段属于第几行
tail -n5 /etc/passwd |awk -F: '{a[NR]=$1}END{for(v in a)print a[v],v}'
打印数组的下标
tail -n5 /etc/passwd |awk -F: '{a[NR]=$1}END{for(i=1;i<=NR;i++)print a[i],i}'
48.统计相同字段出现次数
tail /etc/services |awk '{a[$1]++}END{for(v in a)print a[v],v}'
49.打印blp5
tail /etc/services |awk '/blp5/{a[$1]++}END{for(v in a)print a[v],v}'
50.统计TCP连接状态
netstat -antp |awk '/^tcp/{a[$6]++}END{for(v in a)print a[v],v}'
51.只打印出现次数大于等于 2 的
tail /etc/services |awk '{a[$1]++}END{for(v in a) if(a[v]>=2){print a[v],v}}'
52.不打印重复的行:
tail /etc/services |awk '!a[$1]++'
53.根据指定的字段统计出现次数:
cat << EOF > 1.txt A 192.168.1.1 HTTP B 192.168.1.2 HTTP B 192.168.1.2 MYSQL C 192.168.1.1 MYSQL C 192.168.1.1 MQ D 192.168.1.4 NGINX EOF awk 'BEGIN{SUBSEP="-"}{a[$1,$2]++}END{for(v in a)print a[v],v}' file
54.排序数组:
seq -f "str%.g" 5 | awk '{a[x++]=$0}END{s=asort(a,b);for(i=1;i<=s;i++)print b[i],i}' seq -f "str%.g" 5 |awk '{a[x++]=$0}END{s=asorti(a,b);for(i=1;i<=s;i++)print b[i],i}'
asort 将 a 数组的值放到数组 b, a 下标丢弃,并将数组 b 的总行号赋值给 s,新数组 b 下标从 1 开始 然后遍历
55.替换正则匹配的字符串:
tail /etc/services |awk '/blp5/{sub(/tcp/,"icmp");print $0}'
56.在指定行前后加一行:
seq 5 | awk 'NR==2{sub('/.*/',"txt &")}{print}'
57.统计字段长度:
tail -n 5 /etc/services |awk '{print length($2)}'
58.统计访问 IP 次数:
awk '{a[$1]++}END{for(v in a)print v,a[v]}' access.log
59.统计访问访问大于 100 次的 IP:
awk '{a[$1]++}END{for(v in a){if(a[v]>100)print v,a[v]}}' access.log
60.统计访问 IP 次数并排序取前 10:
awk '{a[$1]++}END{for(v in a)print v,a[v] |"sort -k2 -nr |head -10"}' access.log
61.统计时间段访问最多的 IP:
awk '$4>="[02/Jan/2017:00:02:00" && $4<="[02/Jan/2017:00:03:00"{a[$1]++}END{for(v in a)print v,a[v]}' access.log
62.统计访问 IP 是 404 状态次数:
awk '{if($9~/404/)a[$1" "$9]++}END{for(i in a)print v,a[v]}' access.log
63.将 a 文件相同 IP 的服务名合并:
cat << EOF > a.txt 192.168.1.1: httpd 192.168.1.1: tomcat 192.168.1.2: httpd 192.168.1.2: postfix 192.168.1.3: mysqld 192.168.1.4: httpd awk 'BEGIN{FS=":";OFS=":"}{a[$1]=a[$1] $2}END{for(v in a)print v,a[v]}' a.txt
64.获取 Nginx 负载均衡配置端 IP 和端口:
awk '/example-servers1/,/}/{if(NR>2){print s}{s=$2}}' nginx.conf #example-servers1 为upstream 名
9.shell标准输入 输出和错误
1.打印结果写到文件:
echo "test" > a.txt
2.错误输出结果写到文件:
echo "1 + 1" |bc 2 > error.log
3.标准和错误输出到了空设备。
echo "1 + 1" |bc >/dev/null 2>&1
4.用户输入保存为数组:
read -p "Please input your name: " -a ARRAY Please input your name: a b c echo ${ARRAY[*]}
5.让用户选择是否终止循环 trap 命令定义 shell 脚本在运行时根据接收的信号做相应的处理。
#!/bin/bash trap "func" 2 func() { read -p "Terminate the process? (Y/N): " input if [ $input == "Y" ]; then exit fi } for i in {1..10}; do echo $i sleep 1 done
6.环境变量文件
系统级别
/etc/profile # 系统范围内的环境变量和启动文件。不建议把要做的事情写在这里面,最好创建
一个自定义的,放在/etc/profile.d 下
/etc/bashrc # 系统范围内的函数和别名
用户级别
用户级变量文件对自己生效,都在自己家目录下。
~/.bashrc # 用户指定别名和函数
~/.bash_logout # 用户退出执行
~/.bash_profile # 用户指定变量和启动程序
~/.bash_history # 用户执行命令历史文件
开启启动脚本顺序:
/etc/profile -> /etc/profile.d/*.sh -> ~/.bash_profile -> ~/.bashrc -> /etc/bashrc
本地 80 端口转发到本地 8080 端口
iptables -t nat -A PREROUTING -p tcp --dport 80 -j REDIRECT --to-ports 8080
批量创建用户
#!/bin/bash DATE=$(date +%F_%T) USER_FILE=user.txt echo_color(){ if [ $1 == "green" ]; then echo -e "