shell学习笔记四

awk -F":"  '{print $1}' /etc/passwd
cat /etc/passwd  | awk -F":"  '{print $1}'

$0 代表整行
$NF 代表最后一列
NF 当前awk正在处理的行的字段数
NR 当前awk正在处理的第几行
awk -F: 'BEGIN{ ...处理整个文件前执行的代码... }{ ...处理过程中执行的代码.. }END{...处理完整个文件之后执行的代码...}'


awk  流操作命令

打印所有的行 awk '{print $0}' /etc/passwd 或 awk -F":"  '{print $1}'
打印第一列 awk -F: '{print $1}' /etc/passwd
打印1,3列 awk -F: '{print $1,$3}' /etc/passwd
打印每行的最后一列  awk -F: '{print $NF}' /etc/passwd

打印每行的字段数 awk -F: '{print NF}' /etc/passwd


打印页眉和页尾:

awk  'BEGIN{print "=================These are passwd contents============="} {print $0} END{ print "===============End of Contents==============="}' /etc/passwd

打印所有字段的总数:awk  -F: 'BEGIN{ c=0 } { c=c+NF } END{ print c }' /etc/passwd

 


if ( condition ) {  command } else { command }


打印第八行: awk '{ if ( NR==8 ) { print $0 }   }'  /etc/passwd

关系操作符号:
==  等于  <----#####
!=   不等于
>= 
<=
>
<

打印字段数目大于4的行  awk -F: '{ if ( NF>4 ) {print} }' /tmp/test/passwd
    awk -F: ' NF>4 { print } ' /tmp/test/passwd
打印字段数目大于4的行的总数  awk -F: 'BEGIN{ c=0 } { if (NF>4) { c++ } } END{print c}' /tmp/test/passwd

逻辑操作符:
&&  逻辑与
||    逻辑或
!    逻辑非,取反

打印第5到10行 awk ' NR>=5 && NR<=10  {print}' /etc/passwd
打印uid在30~50范围内的用户名 awk -F: '$3>30 && $3<50 {print $1}' /etc/passwd
隔行打印(隔行删除) awk 'NR%2==0 {print }' /etc/passwd


运算操作符号





^   <--  2^3  2的3次方
++  <-- 自加1
--


利用awk进行算术运算
 echo | awk '{print 1.7/3^4}'

 


# awk -f 01.awk /etc/passwd
[root@dns shell_04]# cat 01.awk
BEGIN{
        FS=":"
}
{
        print $1
}

 

改写成外部脚本调用的形式:

# awk -f 01.awk /etc/passwd
[root@dns shell_04]# cat 01.awk
BEGIN{
        FS=":"
}
{
        print $1
}

 

 


01.sh
awk -F: 'BEGIN{ c=0 } { if (NF>4) { c++ } } END{print c}' /tmp/test/passwd

BEGIN{
  FS=":"
  c=0
}
{
  if (NF>4)
  {
   c++
  }
}
END{
 print c
}

执行: awk -f 201004091/01.sh /etc/passwd


while (condition) statement
do statement while (condition)
              for (expr1; expr2; expr3) statement
              for (var in array) statement

shell的写法:
while [ condition]
do
 command
done

awk 的写法:
while (condition)
{
 command 
}


shell的写法:
until [ condition ]
do
 .....
done


awk的写法:
do

 ....
} while (condition) <---不管开始的时候条件是否成立,都执行一次循环体里的代码


shell的写法:

for ((expr1; expr2; expr3))
do
 .....
done

for var in array
do
 ....
done

awk的写法:

for (expr1; expr2; expr3)

 command

for (var in array)
{
 command
}

 

 

倒序排列所有字段

 


root:x:0:0:tanpao,uplooking,124324324,24235454:/root:/bin/bash
bin:x:1:1:bin:/bin:/sbin/nologin

---》
/bin/bash:/root...:root

for (expr1; expr2; expr3)

 command


思路: 利用一个循环变量i 记录每行字段的总数(7),然后每次循环都答应一个字段
$i --> i--
print $i

for (i=NF;i>0;i--)
{


}

 

BEGIN{
 FS=":"
}
{
 for (i=NF;i>0;i--)
 {
  if ( i!=1 )
  {
   printf("%s%s",$i,FS)
-  }
  else
  {
   #printf("%s%s",$i,"\n")
   printf("%s\n",$i)
  }
 }

 #printf("\n")

}

一行代码模式:
[root@qianxin df]# awk -F: '{for(a=NF;a>0;a--){if(a!=1){printf ("%s%s",$a,FS)}else{printf ("%s\n",$a)}}}' /tmp/passwd
 


%d------------------------数值
%s------------------------字符串

 

字符串的匹配

$0------------------------整行

== -----------------------绝对匹配
$1=="root"
~ ------------------------相对匹配
$1~/root/
!=------------------------不绝对匹配
!~------------------------不相对匹配

输出第一列完全等于root的行
awk -F: '$1=="root"{print $0}' /etc/passwd
 相反:
 awk -F: '$1!="root" {print $0}' /etc/passwd

输出第一列包含root关键字的行
awk -F: '$1 ~ /root/ {print $0}' /tmp/test/passwd
 相反:
awk -F: '$1 !~ /root/ {print $0}' /tmp/test/passwd

awk -F: '! /root/ {print $0}' /tmp/test/passwd <--区别:整行都不包行root


把系统上所有不允许登录的帐号都打印出来,并且最后统计一个数字
/sbin/nologin
/bin/false
单行命令:
#awk -F: 'BEGIN{c=0}$NF~"/sbin/nologin" || $NF~"/bin/false"{printf ("%s\t",$1)}{c++}END{printf "\n%s\n",c}' /tmp/passwd

if , == ,~ ,外部脚本,printf


输出格式:
roy tom mary
total:3

BEGIN{
        FS=":"                     
        a=0
        b=0
}
{
        if ( $7 == "/sbin/nologin" )
                {
                printf ("%s\t",$1)
                a++
                }
        if ($7 == "/bin/false" )
                {
                printf ("%s\t",$1)
                b++
                }
        c=a+b
}
END{
#       c=$a+$b
        printf ("\ntotal:%d\n",c)
}
~                     

只用一行来表示:awk -F: 'BEGIN{a=0}{if($NF~"\/sbin\/nologin" || $NF~"\/bin\/false"){printf ("%s\t",$1);c++}}END{print c}' /etc/passwd


输出格式:
roy tom mary
total:3


BEGIN{
        c=0
        FS=":"
}
{
        if ($NF~/\/sbin\/nologin/ || $NF~/\/bin\/false/)
        {
                printf("%s\t",$1)
                c++
        }

}
END{
        printf("\ntotal:%d\n",c)
}

一行命令的形式
awk 'BEGIN{c=0;FS=":"}{ if ($NF~/\/sbin\/nologin/ || $NF~/\/bin\/false/) { printf("%s\t",$1);c++ } }END{printf("\ntotal:%d\n",c)}'


字符串函数
length([s])
 
BEGIN{
        str="welcome to upl"
}
{
        #print length("welcome to upl")
        print length(str)
}


index(s, t)

BEGIN{
        str="welcome to upl"
}
{
        #print length("welcome to upl")
        print length(str)

        print index(str,"c")   《---返回4,如果找不到,就返回0,如果有多个匹配,就找出第一个匹配
}


改变大小写:
BEGIN{
        str="Welcome to upl"
}
{
        #print length("welcome to upl")
        print length(str)

        print index(str,"l")

        print tolower(str)
        print toupper(str)
}

 


 
例子:把下列的姓名列表中的姓打印出来
提示: 首先找到“,”所在的位置,然后通过子串截取函数,把姓打印出来
Michle,Jackson
Tom,Green
San,Zhang

# cat /tmp/test/name.txt  | awk '{pos=index($0,",");print substr($0,pos+1)}'
Jackson
Green
Zhang

 

例子:要求把用户描述的前15个字符打印出来
San Zhang,He is man,live in shenzhen.
Si Li,He is a gay boy....Do you like him?
Li Xiao,She is a beauty! Everyone likes her!


# cat /tmp/test/name.txt  | awk '{pos=index($0,",");print substr($0,pos+1,15)}'
He is man,live
He is a gay boy
She is a beauty

或者
# cat /tmp/test/name.txt  | awk '{print substr($0,index($0,",")+1,15)}'


字符串替换

sub
gsub

BEGIN{
        str="Welcome to upl"
}
{
        #print length("welcome to upl")
        print length(str)

        print index(str,"l")

        print tolower(str)
        print toupper(str)

        sub("o","-",str)  # 把str中第一个找到的“o”替换成“-”
        print str

        gsub("l","@",str) #把所有匹配都替换
        print str

}


例子:利用awk 找到某个目录下的最大尺寸文件和最小尺寸文件,最后输出所有文件的平均尺寸


Large Size: Max_file.txt
Low Size: Min_file.txt
Avarge Size: 55K

BEGIN{
        total=0
}
{
        total += $5
        if ( NR==1 ){
                print "Max Size:"$5
        }

}
END{
        print "Mini Size:"$5
        print "Average Size:"total/NR
}


传输外部变量进入awk脚本
#awk -v nvar="$a" -f 10.awk

传递shell变量到awk脚本中 
方法一:
# echo | awk -v nvar="$a" -f 10.awk
BEGIN{
        print nvar
}
# echo | awk -v nvar="$a" '{print nvar}'

方法二:

[root@dns shell_04]# export bbb=119
[root@dns shell_04]# echo | awk 'BEGIN{print ENVIRON["bbb"]}'
119

 

方式三:
[root@dns shell_04]# c=007
[root@dns shell_04]# echo | awk 'BEGIN{print "'$c'"}'
007

========================================================================

Tcpwrapper

#ldd /usr/sbin/vsftp | grep wrap
libwrap.so.0<--------------------如果返回值中有调用这种库,则明确支持Tcpwrapper

配置文件/etc/hosts.allow
      /etc/hosts.deny

规则判断的原理:首先去读取hosts.allow文件,如果找到匹配的规则,就停止继续往下匹配,更不去匹配hosts.deny,如果hosts.allow找不到匹配的规则,就读取hosts.deny

# cat /etc/hosts.allow
sshd:10.1.1.0/255.255.255.0 EXCEPT 10.1.1.56
 等价于: 允许10.1.1.1~10.1.1.55 , 10.1.1.57~10.1.1.254的客户IP去访问
# cat /etc/hosts.deny
sshd : 10.1.1.56

以上规则结合起来的作用:仅仅拒绝了10.1.1.56访问sshd

例子:
想只允许10.1.1.0/24网段的客户去访问sshd
# vim hosts.allow
sshd:10.1.1.0/255.255.255.0

# vim hosts.deny
sshd:ALL

或者 只修改一个文件
# vim hosts.allow


# vim hosts.deny
sshd:ALL EXCEPT 10.1.1.0/255.255.255.0


例子: 允许所有人访问,但不允许10.1.1.0/24访问,除了10.1.1.56可以访问之外。
# vim hosts.allow
sshd:ALL EXCEPT   10.1.1.0/255.255.255.0 EXCEPT 10.1.1.56

# vim hosts.deny
sshd:ALL


练习:
 把连续三次企图通过ssh远程登录服务器的恶意IP都添加到tcpwrapper相关的配置文件,把恶意IP拒绝掉。

 规则文件不允许有重复的IP
#lastb -ai | grep ssh | awk '{print $NF}' | uniq -c | awk '$1>=3{print $NF}'

#!/bin/bash

newip=$(lastb -ai | grep ssh | awk '{print $NF}' | uniq -c | awk '$1>=3{print $2}')
oldip=$(cat /etc/hosts.deny  | grep sshd  | awk -F: '{print $2}')
oldtmp=$(mktemp)
echo $oldip > $oldtmp


for a in $newip
do
 grep "$a" $oldtmp > /dev/null
 if [ "$?" -eq 1 ];then
  echo  $(cat $oldtmp) $a > $oldtmp
 fi
done

cat /etc/hosts.deny | grep -v "sshd" > /etc/hosts.deny
echo "sshd: $(cat $oldtmp)" >> /etc/hosts.deny
rm -f $oldtmp
 

你可能感兴趣的:(shell)