Linux13 shell函数、数组及awk、awk中的数组

shell 函数

参考学习:https://www.runoob.com/linux/linux-shell-func.html

function: 功能
结构化编程,不能独立运行,需要调用时执行,可以被多次调用

定义一个函数:
# 方式1:
function FUNCNAME {
    command
}
# 方式2:
FUNCNAME() {
    command
}

自定义执行状态返回值:
return

函数状态返回

返回值在shell中由两种方式
echo  # 返回数据,自定义的输出数据,字符串
return # 命令的执行结果返回值,0-255 之间的正整数  $? 0 默认表示成功  非0表示失败

#!/bin/bash
#
fun() {
echo "123"
return 1
}
Test=$(fun)
echo "函数的状态返回码为:$?"
echo "函数的返回数据为$Test"

bash return-1.sh

函数的状态返回码为:1
函数的返回数据为:123

#!/bin/bash
#
File() {
if [ -f /etc/hosts ];then
  return 0
else
  return 1
}
File && echo "文件存在!" || echo "文件不存在!"
#!/bin/bash
#
function SHOWMENU {
cat << EOF
d|D) show disk usages
m|M) show memory usages
s|S) show swap usages
q|Q quit.
EOF
}
SHOWMENU # shell中的函数调用
read -p "Your choice:" CHOICE
until [ $CHOICE == 'q' -o $CHOICE = 'Q' ];do
case $CHOICE in
d|D) df -lh
m|M) free -m | grep "^Mem"
s|S) free -m | grep "^Swap"
*)
SHOWMENU
read -p "Your Choice,again:" CHOICE
esac
SHOWMENU
read -p "Your choice:" CHOICE
done
#!/bin/bash
#
ADDUSER() {
USERNAME=hdoop
if ! id -u $USERNAME &> /dev/null;then
  useradd $USERNAME
  echo $USERNAME | passwd --stdin $USERNAME &> /dev/null
  return 0
else
  return 1
fi
}

ADDUSER
if [ $? -eq 0 ];then
  echo "add user finished."
else
  echo "Failure."
fi

shell 向函数传递参数

#!/bin/bash
#
TWOSUM() {
echo $[$1+$2]
}
SUM=`TWOSUM 5 6` # 这里的反引号是获取变量的结果
echo $SUM
计算10以内相邻两个数的和

#!/bin/bash
#
TWOSUM() {
echo "$[$1+$2]"
}
for I in {1..10};do
  let J=$[$I+1]
  TWOSUM $I $J
done


#!/bin/bash
#
TWOSUM() {
echo "$1 plus $2 is $[$1+$2]"
}

for I in {1..10};do
  let J=$[$I+1]
  TWOSUM $I $J
done


#!/bin/bash
#
TWOSUM() {
echo $[$1+$2]
}

for I in {1..10};do
  let J=$[$I+1]
  echo "$I plus $J is  `TWOSUM $I $J`"
done
函数返回值在调用该函数后通过 $? 来获得。

#!/bin/bash
#
PING() {
  if ping -c 1 -w 1 $1 &> /dev/null; then
    return 0
  else
    return 1
  fi
}

for I in {200..254};do
  PING 192.168.1.$I
  if [ $? -eq 0 ];then
    echo "192.168.1.$I is up."
  else
    echo "192.168.1.$I is down."
  fi
done 
函数与命令的执行结果可以作为条件语句使用。要注意的是,和 C 语言不同,shell 语言中 0 代表 true,0 以外的值代表 false。

#!/bin/bash
#
PING() {
  if ping -c 1 -w 3 $1 &> /dev/null; then
    return 0
  else
    return 1
  fi
}

for I in {1..15};do
 # PING 192.168.1.$I
  if `PING 192.168.1.$I`;then # 引用的是都是正常输入到屏幕上的信息
  if `PING 192.168.1.$I`;then  # 引用的是函数return的结果,对于if来说,if 0 为真,if 1 为假
    echo "192.168.1.$I is up."
  else
    echo "192.168.1.$I is down."
  fi
done

分发公钥主机脚本

先扫描内网网段的所有主机,存活的主机进行发放本机的公钥

1.删除旧的密钥对,rm 
2.本机是否要有公钥,创建密钥对 ssh-keygen 交互式进行创建、免交互
-f filename # 指定私钥文件保存的路径
-N new_passphrase # 指定一个新的密码
3.批量检测内网主机是否存活 ping
4. 如果存活则发送公钥,确认信息,输入密码 如何进行免交互
-o StrictHostKeyChecking=no #忽略恢复yes的交互(避免第一次交互出现 公钥检查)
sshpass -p123456 # 指定密码为123456,忽略交互

sshpass -p123456 ssh-copy-id -i /root/.ssh/id_rsa.pub -o StrictHostKeyChecking=no 172.16.1.51


#!/bin/bash
#
# 1.调用函数库
[ -f /etc/init.d/functions ] && source /etc/init.d/funcftions || echo "函数库文件不存在!"
# 2. 定义变量
Ip_log=/tmp/ip.log
Port_log=/tmp/port.log
>$Ip_log
>$Port_log
# 3.删除旧的密钥对
rm -rf /root/.ssh
# 4.创建新的密钥对
ssh-keygen -t rsa -f /root/.ssh/id_rsa -N "" &>/dev/null
if [ $? -eq 0 ];then
  echo "密钥对创建成功!"
else 
  echo "密钥对创建失败!"
fi
# 5.批量探测内网主机
i=1
while [ $i -le 25 ];do
  {
    # 6.测试主机网络是否可达
    IP=192.168.1.$i
    ping -c1 -w1 $IP &>/dev/null
    if [ $? -eq 0 ];then
      action "${IP} 地址通畅!" /bin/true
      echo "$IP" >>$Ip_log
     fi
  }&
  let i++
  sleep 0.2
done
wait
echo "Ip地址扫描完毕............."
echo "开始测试远程端口............"
while read line
do
  State=$(nmap -p22 $line | grep -w 22 | awk '{print $2}')
  if [ $State == "open" ];then
    action "IP${line}的远程端口号是开放的........" /bin/true
    echo "${line}" >>$Port_log
  else
    action "IP${line}的远程端口号是关闭的......" /bin/true
  fi
done <$Ip_log
# 7.发送公钥
while read line
  do
    sshpass -p1 ssh-copy-id -p22 -i /root/.ssh/id_rsa.pub -o StrictHostKeyChecking=no $line &>/dev/null 
    if [ $? -eq 0 ];then
      action "${line}的z主机公钥发送成功!" /bin/true
    else
      action "${line}的主机公钥发送失败!" /bin/false
    fi
done <$Port_log

数据库及数据库表备份

#!/bin/bash
#1.定义变量
Db_user=root
Db_pass=123
Date=$(date +%F)
Db_name=$(mysql -u$Db_User -P$dB_Pass -e "show databases;" | sed ld | grep -v ".*_schema")
for Database_Name in $Db_name;do
  # 2. 判断单独的数据库备份目录是否存在
  Back_Dir=/backup/$Database_Name
  [ -d $Back_Dir ] || mkdir -p $Back_dir
  # 3. 备份数据库
  mysqldump -u$Db_User -p$Db_Pass --single-transaction -B $Database_Name > $Back_Dir/${Database_Name}_${Date}.sql
  if [ $? -eq 0 ];then
    echo -e "\033[42;37m${Database_Name}数据库备份成功! \033[0m"
  else
    echo -e "\033[41;37m${Database_Name}数据库备份失败! \033[0m"
  fi
  # 开始备份表
  Tb_name=$(mysql -u$Db_User -p$Db_Pass -e "use $Database_Name;show tables;" |sed ld)
  for Table_Name in $Tb_name;do
    mysqldump -u$Db_User -p$Db-Pass --single-transaction $Database_Name $Table_Name > $Back_Dir/${Database_Name}_${Table_Name}_${Data}.sql
    if [ $? -eq 0 ];then
      echo -e "\033[42;37m${Database_Name}数据库下的$:{Table_Name}表备份成功! \033[0m"
    else
      echo -e "\033[42;37m${Database_Name}数据库下的${Table_Name}表备份失败! \033[0m"
    fi
  done
done

系统工具箱脚本

#1.编写菜单
menu() {
cat <<EOF
##########################
1. 显示磁盘的使用情况
2. 显示内存使用情况
3. 显示是系统负载情况
4. 显示CPU使用情况
5. 查看系统Eth0网卡
6. 查看系统外网IP
7. 查看系统版本
8. 查看系统内核版本
9. 退出脚本程序
0. 显示帮助菜单
###########################
EOF
}
let I=0
while [ $I -lt 3 ]; do
  menu
  # 2.提示用户输入要查看的信息
  read -p "请根据上方菜单进行选择要查看的信息:" Num
  if [ $Num -gt 9 ];then
    I=$(($I+1))
    echo "这是您第${I}输错了,您还有$((3-$I))次机会尝试。"
  fi
  # 3. 根据用户输入的数字进行编写case语句
  case $Num in
    1)
      echo "系统磁盘使用情况如下:"
      df -h
      ;;
    2) 
      echo "系统内存使用情况如下:"
      free -m
      ;;
    3) 
      echo "系统负载情况如下:"
      uptime  # 或者使用 w
      ;;
    4)
      echo "系统CPU使用情况如下:"
      top
      ;;
    5)
      echo "系统的Eth0网卡IP地址如下:"
      ifconfig ens33 | awk 'NR==2{print $2}'
      ;;
    6) 
      echo "系统的外网IP地址如下:"
      curl -s ifconfig.me
      echo
      ;;
    7)
      echo "操作系统版本如下:"
      awk '{print $1,$4}' /etc/redhat-release
      ;;
    8) 
      echo "系统内核版本如下:"
      uname -r
      ;;
    9)
      echo "脚本程序退出!"
      exit 0
      ;;
    0)
      menu
      ;;
    *)
      echo "输入错误,根据菜单选择对应功能。"
      ;;
  esac  
done 
echo "您3次输入机会已经全部用完。。。。告辞。。。。"
exit 1

实现简单的Jumpserver

1.执行脚本后,显示菜单,菜单内容所有可管理的主机
2.选择菜单一个选项,连接对应的主机
3.需要进行死循环,连接成功一个主机之后,退出还能继续连接其他的主机
4.不能让其使用Ctrl c d z等操作
5.退出当前脚本的会话,再次登陆时,还是自动的执行脚本,不能操作后台的操作 /etc/bashrc  /etc/profile
6.留一个出口,不让别人知道

菜单
###########################
1. 管理web01-10.0.0.7
2. 管理web02-10.0.0.8
3. 管理web03-10.0.0.9
###########################

#!/bin/bash
#
#1.定义函数菜单
menu() {
cat<<EOF
###########################
1. 管理web01-10.0.0.7
2. 管理web02-10.0.0.8
3. 管理web03-10.0.0.9
4. 显示主机列表
###########################
EOF
}

ssh_login() {
# 7. 测试对应的主机IP是否能Ping通
ping -c1 -w1 $2 &> /dev/null
if [ $? -eq 0 ];then
  echo "正在连接Web$1-$2主机..."
  ssh root@$2
else
  echo "web01的主机网络不可达!无法进行远程连接!"
fi
}

# 3.禁止输入Ctrl+c、d、z等操作
trap "" HUP INT TSTP
# 4.进行循环操作
while true;do
  # 2.打印菜单
  menu
  # 5. 提示用户输入对应的编号
  read -p "请根据上方菜单的主机列表,进行选择要连接的主机[1|2|3|4]:" Num
  # 6.根据选项进行编写case语句
  case $Num in
  1)
    clear
    ssh_login 01 10.0.0.7
    ;;
  2)
    clear
    ssh_login 02 10.0.0.8
    ;;
  3)
    clear
    ssh_login 03 10.0.0.9
    ;;
  4) 
    clear # 清屏操作
    ;;
  anhao)
    echo "内部人员才能执行的操作!退出程序!进入后台管理!"
    exit 0
    ;;
  *)
    echo "你输入的不符合要求!请根据菜单进行选择要连接的主机!"
    clear
    ;;
  esac
done


# 在/etc/bashrc 和/etc/profile下添加执行脚本的路径,在登录后自动执行jumpserver.sh脚本
/bin/bash /root/shell_scripts/jumpserver.sh

随机点名脚本

1.要有名单
2.随机的打印这些名单
3.打印最后一个出现的人员名字
4.找一个随机数,随机数是整数,且不能小于1和大于人员总数
    echo $((25 % 26 +1))

#!/bin/bash
#
#1.定义变量,人员总数
Number=$(wc -l student.txt |awk '{print $1}')
#2.进行循环,由用户定义循环多少次
read -p "请输入循环的次数:" Num
#3.进行循环
for i in $(seq $Num);do
  #4.随机取得一个数字,但是此数字不能大于文件的总行数
  Stu_Num=$((RANDOM % $Number +1))
  #5.循环一次,就打印一次人员名单
  sed -n "$({Stu_Num}p" student.txt)
  #6.等待0.5s之后,继续打印
  sleep 0.5
done
#7.打印出最后一次循环的人员名单
Stu_Name=$(sed -n "${Stu_Num}p" student.txt)
echo -e "天选子:\033m[32m$Stu_Name\033[0m" 

shell中的数组

# 定义数组
# 声明数组 
declare -a 数组名 普通数组无需声明

# 第一种定义方式
shuzu_1[0]=nginx
shuzu_1[1]=php-fpm
shuzu_1[2]=mysql

# 第二种定义方式,一次定义多个值
shuzu_2=(name age hobby)

# 第三种 通过命令的执行结果进行定义,默认以空白字符为分隔符
shuzu_3=($(cat /etc/hosts))

# 第四种方式 自定义索引序列号
shuzu_4=(beijing shanghai [5]=wuhan [10]=nanjing)

# 访问数组中的内容

# 打印数组中所有的值
echo ${shuzu_1[@]}
nginx php-fpm mysql

# 打印数组的所有的索引
echo ${!shuzu_1[@]}
0 1 2 

# 打印数组的元素个数(索引的个数)
echo ${#shuzu_1[@]}
3

# 显示定义的普通数组
declare -a

# 取出数组中单个的值
echo ${shuzu_1[0]}
nginx
echo ${shuzu_1[1]}
php-fpm
echo ${shuzu_1[2]}
mysql

# 打印数组中的从索引1开始打印,显示所有。
echo ${shuzu_1[@]:1}
pyh-fpm mysql

# 打印数组中的从索引0开始打印,显示所有
echo ${shuzu_1[@]:0}
nginx php-fpm mysql

# 打印数组中的从索引2开始打印,显示所有
echo ${shuzu_1[@]:2}
mysql

# 打印数组从索引0开始,打印1个索引
echo ${shuzu_1[@]:0:1}
nginx
echo ${shuzu_1[@]:0:2}
nginx php-fpm
echo ${shuzu_1[@]:0:3}
nginx php-fpm mysql



url=www.baidu.com
echo ${url:1:5}
ww.ba

正则表达式之Awk

awk 是一个编程语言
主要作用:对文本和数据的处理

# awk处理数据的流程
1.扫描文件内容,从上到下进行扫描,按照行进行处理的;
2.寻找匹配到的内容,进行读取到特定的模式中,进行行处理;
3.行满足指定的模式动作,则输出到屏幕上面,不满足丢弃;
4.接着读取下一行继续处理,接着循环,直到文件的结尾;

awk 语法格式
awk [选项] command files

三种格式

行处理前        行处理中       行处理后
BEGIN          执行的命令      最后的显示

# 行处理前
[root@shell ~]# awk 'BEGIN{print 1 +1}'
2

# 行处理前+行处理后
[root@shell ~]# awk -F: '{print $1}' /etc/passwd
root
bin
daemon

[root@shell ~]# awk 'BEGIN{FS=":"}{print $1}' /etc/passwd
root
bin
daemon

# FS指定输入分隔符;OFS 指定输出分隔符;不指定的话,当print多列时,多列之间的逗号会默认被空格取代。
[root@shell ~]# awk 'BEGIN{FS=":";OFS="###"}{print $1,$2}' /etc/passwd
root###x
bin###x
daemon###x
adm###x



# 行处理前+行处理中+行处理后
[root@shell ~]# awk 'BEGIN{FS=":";OFS="###"}{print $1,$2}END{print "内容打印结束"}' /etc/passwd
root###x
bin###x
daemon###x
adm###x
lp###x
sync###x
shutdown###x
halt###x
operaror###x
games###x
内容打印结束

[root@shell ~]# awk 'BEGIN{FS=":";OFS="###"}{print $1,$2"内容打印结束"} /etc/passwd
root###x内容打印结束
bin###x内容打印结束
daemon###x内容打印结束
adm###x内容打印结束
lp###x内容打印结束
sync###x内容打印结束
shutdown###x内容打印结束
halt###x内容打印结束
mail###x内容打印结束
operator###x内容打印结束
games###x内容打印结束
ftp###x内容打印结束
nobody###x内容打印结束
systemd-network###x内容打印结束
dbus###x内容打印结束
polkitd###x内容打印结束
sshd###x内容打印结束
postfix###x内容打印结束
apache###x内容打印结束
dockerroot###x内容打印结束
user1###x内容打印结束
user2###x内容打印结束

# 行前计算1+1 行中打印OK 显示5次是因为hosts中有5行内容,行后打印 内容显示结束
[root@zhang ~]# awk 'BEGIN{print 1+1}{print "OK"}END{print "内容显示结束"}' /etc/hosts
2
OK
OK
OK
OK
OK
内容显示结束
[root@zhang ~]# cat /etc/hosts
127.0.0.1   localhost localhost.localdomain localhost4 localhost4.localdomain4
::1         localhost localhost.localdomain localhost6 localhostl6.localdomain6
192.168.1.1 home-gateway home
192.168.1.7 www.chaozhang.com
192.168.1.7 www.a.org

test.txt
10 10 10
[root@zhang ~]# awk '{print $1 + $2}' test.txt
20

awk 'BEGIN{FS=":";OFS="\n"}{for(i=1;i<=NF;i++) {print $i}}' /etc/passwd

awk的工作原理

1.awk将文件中每一行作为输入,将每一行的数据复制给内部变量 $0;
2.awk又开始进行字段分解,根据指定的分隔符,将每个字段进行赋值给内部变量 $1 $2 $3;
3.awk默认的分割为空白字符,由内部变量FS来确定,也可以使用-F进行指定对应的分隔符;
4.awk处理时使用print进行打印你分割后的字段;
5.awk打印输入结果之后,不同字段之间由空格进行分割,这个空格是由不同字段之间的逗号进行映射的,由内部变量OFS进行修改,OFS默认的输出分割符就是空格;
6.awk输出一行内容之后,从新读取下一行内容,会覆盖内部变量$0,然后新的字段分割并进行处理;

awk的命令格式

匹配       模式       动作

# 匹配    模式
[root@zhang ~]# awk '/root/' /etc/passwd
root:x:0:0:root:/root:/bin/bash
operator:x:11:0:operator:/root:/sbin/nologin
dockerroot:x:998:995:Docker User:/var/lib/docker:/sbin/nologin

#动作
[root@zhang ~]# awk '{print $1}' /etc/passwd
root:x:0:0:root:/root:/bin/bash
bin:x:1:1:bin:/bin:/sbin/nologin
daemon:x:2:2:daemon:/sbin:/sbin/nologin
adm:x:3:4:adm:/var/adm:/sbin/nologin

# 模式+动作
[root@zhang ~]# awk -F: '/root/{print $1}' /etc/passwd
root
operator
dockerroot


[root@zhang ~]# df 
Filesystem                  1K-blocks     Used Available Use% Mounted on
devtmpfs                      1913708        0   1913708   0% /dev
tmpfs                         1930640        0   1930640   0% /dev/shm
tmpfs                         1930640    20716   1909924   2% /run
tmpfs                         1930640        0   1930640   0% /sys/fs/cgroup
/dev/mapper/rhel_zhang-root  52403200 13948448  38454752  27% /
/dev/mapper/myvg-testlv       5095040     4160   4860264   1% /users
/dev/sda1                      508580   259724    248856  52% /boot
tmpfs                          386128        0    386128   0% /run/user/0
[root@zhang ~]# df | awk '/\/$/{print $3}'
13948448

# 当根分区的使用率大于多少时则打印第三列
[root@zhang ~]# df | awk '/\/$/{if ($3>13000000) print $3}'
13948448

awk数组概述

将需要统计的某个字段作为数组的索引,然后对索引进行遍历

统计/etc/passwd文件中每种shell的数量

# 方法一:使用shell的数组

#!/bin/bash
#
declare -A array
while read line
do
  N=`echo $line | awk -F: '{print $NF}'`
  let array[$N]++

done</etc/passwd
for i in ${!array[*]}
do
  echo $i ${array[$i]}
done


# 方法二: 使用awk的数组
awk -F: '{array[$NF]++}END{for(i in array) print i,array[i]} /etc/passwd'

/bin/sync 1
/bin/bash 14
/sbin/nologin 44
/sbin/halt 1
/sbin/shutdown 1

站访问状态统计<当前实时状态ss>

ss -an | awk '/:80/{tcp[$2]++} END {for(i in tcp){print i,tcp[i]}}'


[root@zhang shell_script]# ss -an | awk '/:80/{tcp[$2]++} END {for(i in tcp){print i,tcp[i]}}'
LISTEN 1

统计当前访问的每个IP的数量<当前实时状态netstat,ss>

ss -an | awk -F: '/80/{ips[$(NF-1)]++}END{for(i in ips){print i,ips[i]}}'

统计2018年01月25日当天的PV量

grep "25/Jan/2018" log.bjstack.log | wc -l
awk "/25\/Jan\/2018/" log.bjstack.log | wc -l
awk '/25\/Jan\/2018/ {ips[$1]++} END {for(i in ips) {sum+=ips[i]} {print sum}}' log.bjstack.log

统计15-19点的PV量

awk '$4>="[25/Jan/2018:15:00:00" && $4<="[25/Jan/2018:19:00:00 {print $0}"' log.bjstack.log | wc -l

统计2018年01月25日,一天内访问最多的10个IP

awk '/25\/Jan\/2018/ {ips[$1]++} END {for(i in ips){print ips[i],i}}' log.bjstack.log |sort -rn | head

统计2018年01月25日访问大于100次的IP

awk '/25\/Jan\/2018/ {ips[$1]++} END {for(i in ips){if(ips[i]>10){print i,ips[i]}}}' log.bjstack.log

统计2018年01月25日访问最多的10个页面($request top 10)

awk '/25\/Jan\/2018/ {request[$7]++}END{for(i in request){print request[i],i}}' log.bjstack.log |sort -rn 
head

统计2018年01月25日每个URL访问内容总发小(¥body_bytes_sent)

awk '/25\/Jan\/2018/ {request[$7]++;size[$7]+=$10} END {for(i in reqeust){print request[i],i,size[i]}}' log.bjstack.log | sort -rn | head

统计2018年01月25日每个IP访问状态码数量($status)

awk '{ip_code[$i " " $9]++} END {for(i in ip_code){print ip_code[i],i}}' log.bjstack.log | sort -rn | head

统计2018年01月25日访问状态码为404及出现的次数($status)

grep "404" log.bjstack.log | wc -l
awk '{if($9="404") code[$9]++} END {for(i in code){print i,code[i]}}' log.bjstack.log

统计2018年01月25日8:30-9:00访问状态时404

awk '$4>="[25/Jan/2018:15:00:00" && $4<="[25/Jan/2018:19:00:00" && $9=="404" {code[$9]++} END {for(i in code){print i,code[i]}}' log.bjstack.log

awk '$9=="404" {code[$9]++} END {for(i in code){print i,code[i]}}' log.bjstack.log

统计2018年01月25日各种状态码数量,统计状态码出现的次数

awk '{code[$9]++} END {for(i in code){print i,code[i]}}' log.bjstack.log

awk '{if($9>=100 && $9<200) {i++}}'

Awk内部变量

# '$0'保存当前记录的内容
awk '{print $0}' /etc/passwd

# 'NR'记录输入总的编号(行号)
awk '{print NR,$0}' /etc/passwd
awk 'NR<=3' /etc/passwd 

# 'FNR'给输入的多个文件的行总体一次性编号(行号)
awk '{print NR,$0}' /etc/passwd /etc/shadow /etc/group
'FNR'给输入的每个文件的行单独编号(行号)
awk '{print FNR,$0}' /etc/passwd /etc/shadow /etc/group

# 'NF'保存行的最后一列
NF 代表一行有多少个域 (也就是一行有多少个单词)
$NF代表最后一个域 (也就是最后一个单词)

awk -F: '{print NF,$NF}' /etc/passwd 

[root@zhang shell_script]# awk -F: '{print NF,$NF}' /etc/passwd 
7 /bin/bash
7 /sbin/nologin
7 /sbin/nologin
7 /sbin/nologin
7 /sbin/nologin
7 /bin/sync
7 /sbin/shutdown
7 /sbin/halt
7 /sbin/nologin
7 /sbin/nologi

# 'FS 指定字段输入分隔符,默认时空格'
以冒号作为字段分隔符
awk -F: '/root/{print $1,$3}' /etc/passwd
awk 'BEGIN{FS=':'}{print $1,$3}' /etc/passwd
awk -F'[ :\t]' '{print $1,$2,$3}' /etc/passwd

# 'OFS'指定输出字段分隔符
逗号映射为OFS,初始情况下OFS变量是空格
awk -F: '/root/{print $1,$2,$3,$4}' /etc/passwd
awk 'BEGIN{FS=":";OFS="+++"}' '/root/{print $1,$2}' /etc/passwd

# 'RS'输入记录分隔符,默认为换行符(了解)
awk -F: 'BEGIN{RS=" "} {print $0}' /etc/hosts 

# 'ORS'将文件以空格为分割符,将每一行合并为一行(了解)
awk -F: 'BEGIN{ORS=" "} {print $0}' /etc/hosts 

# 'print'格式化输出函数
date | awk '{print $2,"5月份""\n",$NF,"今年"}'
awk -F: '{print "用户是" $1 "\t 用户uid:" $3 "\t 用户gid:" $4}' /etc/passwd

# printf函数
awk -F: '{printf "%-15s %-10s %-15s\n",$1,$2,$3}' /etc/passwd

%s  字符类型
%d  数值类型
占15字符
- 表示左对齐,默认是右对齐
printf 默认不会再行尾自动换行, 加\n

# 匹配记录(整行)
awk '/^root/' /etc/passwd
awk '$0 ~ /^root/' /etc/passwd

# 匹配字段:匹配操作符(~ !~)
awk '$1~/^root/' /etc/passwd
awk '$NF !~ /bash$/' /etc/passwd

# 比较表达式
比较表达式采用对文本进行比较,只有当条件为真,才执行指定的动作
比较表达式使用关系运算符,用于比较数字与字符串。

关系运算符

运算符				含义				示例
<				  小于			   x<y
<=				小于或等于			 x<=y
==				   等于			   x==y
!=				  不等于              x!=y
>=                 大于等于            x>=y
>                   大于               x>y

uid为0的列出来
awk -F ":" '$3==0' /etc/passwd
uid小于10的全部列出来
awk -F: '$3 < 10' /etc/passwd
用户登录的shell等于/bin/bash
awk -F: '$7 == "/bin/bash"' /etc/passwd
第一列alice的列出来
awk -F: '$1 == "alice"' /etc/passwd
磁盘使用率大于多少则打印可用的值
df | awk '/\/$/' | awk '$3>1000000 {print $4}' /etc/passwd

# 条件表达式
awk -F: '$3>300 {print $0}' /etc/passwd
awk -F: 'if($3>300) print $0' /etc/passwd
awk -F: '{if($3>5555){print $3} else{print $1}}' /etc/passwd

# 运算表达式
awk -F: '$3 * 10>500000' /etc/passwd
awk -F: 'BEGIN{OFS="--"}{if($3*10>50000) {print $1,$3}} END {print "打印ok"}' /etc/passwd
awk '/southem/{print $5+10}' datafile
awk '/southem/{print $5+10.56}' datafile
awk '/southem/{print $8-10}' datafile
awk '/southem/{print $8/2}' datafile
awk '/southem/{print $8*2}' datafile
awk '/southem/{print $8 % 2}' datafile

# 逻辑操作符和复合模式
&& 逻辑与  || 逻辑或  !逻辑非

匹配用户名为root并且打印uid小于15的行
awk -F: '$1~/root/ && $3<=15' /etc/passwd
匹配用户名为root或uid大于5000
awk -F: '$1~/root/ || $3>=5000' /etc/passwd


awk '{print NF}' b.txt
awk -F: '{print NF}' b.txt
awk -F "[: ]" '{print NF}' b.txt

Awk条件判断


打印当前管理员用户名称
awk -F: '{if($3==0){print $1,"is administrator"}}' /etc/passwd

统计系统用户数量
awk -F: '{if($3>0 && $3<1000){i++}} END {print i}' /etc/passwd

统计普通用户数量
awk -F: '{if($3>1000){i++}} END {print i}' /etc/passwd



if...else 语句格式:{if(表达式) {语句;语句;...} else {语句;语句;...}} 

awk -F: '{if($3==0){print $1} else {print $7}}' /etc/passwd
awk -F: '{if($3==0) {count++} else{i++}}' /etc/passwd
awk -F: '{if($3==0) {count++} else(i++)} END{print "管理员个数:"count;print"系统用户数:" i}' /etc/passwd



if...elseif...else 语法格式:
{if(表达式1) {语句;语句;...}else if(表达式2) {语句;语句;...} else {语句;语句;...}}

awk -F: '{if($3==0){i++} else if($3>0 && $3<1000){i++} else if($3>1000) {k++}} END {print i;print j;print k}' /etc/passwd

awk -F: '{if($3==0){i++} else if($3>0 && $3<1000){j++} else if($3>1000) {k++}} END {print "管理员个数"i;print "系统用户个数:" j; print "系统用户个数:" k}' /etc/passwd

Awk循环语句

while 循环

awk 'BEGIN{i=i;while(i<=10){print i;i++}}'

awk -F: '{i=1; while(i<=NF){print $i;i++}}' /etc/passwd

awk -F: '{i=1; while(i<=10){print $0;i++}}' /etc/passwd

cat b.txt

111 222
333 444 555
666 777 888 999

awk '{i=1;while(i<=NF){print $i;i++}}' b.txt

awk的for循环

C风格for
awk 'BEGIN {for(i=1;i<=5;i++){print i}}'

将每行打印10次
awk -F: '{for(i=1;i<=10;i++){print $0}}' /etc/passwd
awk -F: '{for(i=1;i<=10;i++){print $0}}' /etc/passwd
awk -F: '{for(i=1;i<=NF;i++){print $0}}' /etc/passwd
posted on 2021-05-14 04:27  jueyuanfengsheng  阅读(220)  评论(0编辑  收藏  举报