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