1、正则表达式
什么时正则表达式?与通配符有什么区别?——— 正则表达式一般是在文件中搜索内容,是包含匹配;而通配符表示是在文件夹中搜索文件,是完全匹配;
grep、awk、sed等命令都可以支持正则表达式,而ls、find、cp等是不支持正则表达式。
基础正则表达式其相关元字符以及含义如下表所示:
以上需要记住;
扩展正则表达式
扩展正则表达式需要使用grep -E命令,一般使用的也不是很多。其元字符和具体含义如下表所示:
知道就行;
范例1:匹配邮箱
[0-9a-zA-Z_]+@[0-9a-zA-Z_]+(\.[0-9a-zA-Z_]+){1,3}
范例2:匹配IP
^(([0-9]\.)|([1-9][0-9]\.)|(1[0-9][0-9]\.)|(2[0-4][0-9]\.)|(25[0-5]\.)){3}(([0-9]\.)|([1-9][0-9]\.)|(1[0-9][0-9]\.)|(2[0-4][0-9]\.)|(25[0-5]\.))$
2、字符截取和替换命令
cut提取命令
如下,一般前面两条使用比较多。cut的默认分隔符是制表符(tab键),对于空格符来做分隔符不支持;
对于要提取多列,列与列之间用逗号“,”隔开即可。
awk编程
当用空格来做分割符号时,cut就不能直接提取行了,需要用到awk来进行行提取。了解awk之前需要先学习printf函数,一般与awk搭配使用。
printf格式化输出
其中printf表达式中输出内容一般是执行某条命令的结果。例如printf '%s \t %s \t %s \t \n' $(cat test.txt),个人理解文件内容默认使用空格进行分隔了,其中printf表达式中输出类型输出格式中的空格不会体现在printf的输出结果中。
awk基本使用
注意,对于没有条件的awk命令,直接按动作中的内容进行输出。
示例1:输出文件test.txt的第一列与第三列
awk '{printf $2 "\t" $3 "\n"}' test.txt
示例2:输出df -h返回的/dev/sda1行的第五列与第6列内容。此时使用的是print,默认最后自带换行
[root@jone ~]# df -h
文件系统 容量 已用 可用 已用% 挂载点
/dev/mapper/centos-root 23G 1.7G 22G 8% /
devtmpfs 232M 0 232M 0% /dev
tmpfs 244M 0 244M 0% /dev/shm
tmpfs 244M 4.5M 240M 2% /run
tmpfs 244M 0 244M 0% /sys/fs/cgroup
/dev/sda1 1014M 132M 883M 13% /boot
tmpfs 49M 0 49M 0% /run/user/0
[root@jone ~]# df -h | grep /dev/sda1 | awk '{print $5 "\t" $6}'
13% /boot
awk与cut配合使用:
[root@jone ~]# df -h | grep /dev/sda1 | awk '{print $5}' | cut -d "%" -f 1
13
awk条件判断:
注意,BEGIN是awk程序一开始时还未读取数据前执行,END则是处理完数据后执行。
awk内置变量如下:(主要是FS及之前的几个常用,其他的用的少)
一般这些内置变量和条件判断、awk基本语法都是综合运用的;
举例1:用:分隔符对passwd中的内容进行分隔,输出第三列为1000的用户名
备注:由于awk默认先读取第一行$0,不加BEGIN参数时不会对第一行进行:分隔而是直接输出。另外,awk的内容读取时逐行进行读取的;
[root@jone ~]# cat /etc/passwd | grep "/bin/bash"
root:x:0:0:root:/root:/bin/bash
zhangli:x:1000:1000:zhangli:/home/zhangli:/bin/bash
li:x:1001:1001::/home/li:/bin/bash
[root@jone ~]# cat /etc/passwd | grep "/bin/bash" | awk 'BEGIN{FS=":"} $3=="1000" {print($1)}'
zhangli
举例2:用:进行分隔,并输出第一列和第三列的数值,写出其行号和字段数(理解也是列数)
[root@jone ~]# cat /etc/passwd | grep /bin/bash
root:x:0:0:root:/root:/bin/bash
zhangli:x:1000:1000:zhangli:/home/zhangli:/bin/bash
li:x:1001:1001::/home/li:/bin/bash
[root@jone ~]# cat /etc/passwd | grep "/bin/bash" | awk 'BEGIN {FS=":"} {printf($1 "\t" $3 "\t 行号:" NR "\t 字段数:" NF "\n")}'
root 0 行号:1 字段数:7
zhangli 1000 行号:2 字段数:7
li 1001 行号:3 字段数:7
[root@jone ~]#
sed命令
一般在程序修改数据,使用sed对数据进行增删改查。
举例1:在test.txt文件的第二行后添加一行,内容为1111,这种方式不会直接修改文件,只是显示
[root@jone ~]# sed '2a 1111' test.txt
num name score
1 zl 99
1111
2 ls 98
3 ts 99
4 wk 78
举例2:在例子1基础上,若要直接修改文件则需要加-i参数
[root@jone ~]# sed -i '2a 1111' test.txt
[root@jone ~]# cat test.txt
num name score
1 zl 99
1111
2 ls 98
3 ts 99
4 wk 78
[root@jone ~]#
举例3:对文件test.txt中内容,删除第二行
sed -i '2d' test.txt
举例4:对文件test.txt中的内容,替换某个字段
不注明行范围,表示对整个文件的内容字段进行替换
sed 's/zl/zm/g' test.txt
其他的请参考命令说明即可。
字符处理命令
sort排序命令
实例1:将/etc/passwd文件以:作为分隔符,按第三列的数值大小顺序进行排序
[root@jone ~]# sort -n -t ":" -k 3,3 /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
lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
sync:x:5:0:sync:/sbin:/bin/sync
shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown
halt:x:7:0:halt:/sbin:/sbin/halt
mail:x:8:12:mail:/var/spool/mail:/sbin/nologin
operator:x:11:0:operator:/root:/sbin/nologin
games:x:12:100:games:/usr/games:/sbin/nologin
ftp:x:14:50:FTP User:/var/ftp:/sbin/nologin
apache:x:48:48:Apache:/usr/share/httpd:/sbin/nologin
sshd:x:74:74:Privilege-separated SSH:/var/empty/sshd:/sbin/nologin
dbus:x:81:81:System message bus:/:/sbin/nologin
postfix:x:89:89::/var/spool/postfix:/sbin/nologin
nobody:x:99:99:Nobody:/:/sbin/nologin
dhcpd:x:177:177:DHCP server:/:/sbin/nologin
systemd-network:x:192:192:systemd Network Management:/:/sbin/nologin
chrony:x:998:996::/var/lib/chrony:/sbin/nologin
polkitd:x:999:998:User for polkitd:/:/sbin/nologin
zhangli:x:1000:1000:zhangli:/home/zhangli:/bin/bash
li:x:1001:1001::/home/li:/bin/bash
zhang:x:1002:1002::/home/zhang:/sbin/nologin
lisi:x:1003:1003::/home/lisi:/sbin/nologin
user1:x:1004:1004::/home/user1:/sbin/nologin
uniq
取消重复行,等价于sort -u,这样保证在输出内容时重复行只输出一行(只比较相邻两行);
wc
统计命令,之前已经学习过,不再讲;
uniq与sort -u
由于uniq只是检查相邻两行重复情况,而sort -u进行去重时会对原有数据进行排序。对于针对即要去重又要保持原有序列的需求时候,sort与uniq就比较难搞,通过下面的办法来进行实现:
cat 【对应文本】 |awk '{if(!($0 in a)){print $0};a[$0];}' > result.txt(重定向到result.txt文件)
条件判断
1、按文件类型进行判断
图中标红的为常用功能项。一般格式为[ 测试选项 文件 ],一般用在if语句中。
举例:测试/etc/passwd这个文件是否存在并是否为非空
[root@jone ~]# [ -s /etc/passwd ] && echo yes || echo no
yes
2、按文件权限进行判断
举例,判断文件/etc/passwd是否具有写权限,其实是判断整个,只要有写权限都会是真
[root@jone ~]# ll /etc/passwd
-rw-r--r-- 1 root root 1163 12月 15 23:04 /etc/passwd
[root@jone ~]#
[root@jone ~]# [ -w /etc/passwd ] && echo yes || echo no
yes
3、判断两个文件,之间进行比较
一般第三个用的还稍微多点,其他用的不多。
4、两个整数之间进行比较
比较简单,不进行细讲了
5、字符串的判断
6、多重条件判断
流程控制语句
if单分支
其格式如下:条件判断式使用上面所讲的test判断式,条件判断式与中括号间都是有空格的。
或者
举例:取出/dev/sda1的磁盘利用率,如果大于10就报警111111
[root@jone ~]# cat dd.sh
#!/bin/bash
aa=$(df -h | grep /dev/sda1 | awk '{print $5}' | cut -d "%" -f 1)
if [ "$aa" -ge 10 ]
then
echo "111111"
fi
if双分支
增加一个知识点:一般执行脚本过程中不想要看相关的输出,因为没什么意义,因而可以把对应输出(正确或错误)直接&>放进/dev/null(垃圾箱)中。
if多分支
举例:linux里做一个计算器
[root@jone ~]# cat caculator.sh
#!/bin/bash
echo "欢迎使用计算器"
read -t 30 -p "please input a number1: " num1
read -t 30 -p "please input a number2: " num2
read -t 30 -p 'please input a operator:+-*/ ' oper
if [ -n "$num1" -a -n "$num2" -a -n "$oper" ]
then
test1=$( echo "$num1" | sed 's/[0-9]//g' )
test2=$( echo "$num2" | sed 's/[0-9]//g' )
if [ -z "$test1" -a -z "$test2" ]
then
if [ "$oper" == "+" ]
then
sum=$(($num1+$num2))
elif [ "$oper" == "-" ]
then
sum=$(($num1-$num2))
elif [ "$oper" == "*" ]
then
sum=$(($num1*$num2))
elif [ "$oper" == '/' ]
then
sum=$(($num1/$num2))
else
echo "the format of operator input is wrong: $oper "
exit 10
fi
else
echo "the format of input is wrong: $num1,$num2"
exit 11
fi
else
echo "请输入对应的内容"
exit 20
fi
echo "$num1 $oper $num2 = $sum "
case语句
做的一层判断。if多分支可以做多层判断。case语句语法格式为:
举例:简单一层判断,可以简化代码
[root@jone ~]# cat case.sh
#!/bin/bash
echo "wantobeijing,please choose 1"
echo "wantoshanghai,please choose 2"
echo "wantochengdu,please choose 3"
read -t 30 -p "please input your choice: " choice
case $choice in
"1")
echo "beijing11111"
;;
"2")
echo "shanghai22222"
;;
"3")
echo "chengdu33333"
;;
*)
echo "error input"
;;
esac
for循环语句
其语法如下,都在用,都重要。
语法1:
语法2:
语法1举例:
[root@jone ~]# cat for.sh
#!/bin/bash
for i in 1 2 3
do
echo $i
done
语法2举例:
[root@jone ~]# cat for2.sh
#!/bin/bash
sum=0
for (( i=1;i<=100;i=i+1 ))
do
sum=$(( $sum+$i ))
done
echo $sum
在某些时候语法1比语法2更是合适在shell脚本语言里进行编程。
例如:过滤目录中的压缩文件并对其进行操作,下面那种语法相对更简单,for i in $(命令)也是对$(命令)输出内容的每一行/空格间隔开的数进行遍历;
while循环
语法如下:
举例:
[root@jone ~]# cat while.sh
#!/bin/bash
i=1
s=0
while [ $i -le 100 ]
do
s=$(( $s+$i ))
i=$(( $i+1 ))
done
echo $s
until语句
语法如下,与while语句意思相反,当条件判断式不成立时执行下面的语句;
例子:
[root@jone ~]# cat until.sh
#!/bin/bash
i=1
s=0
until [ $i -gt 100 ]
do
s=$(( $s+$i ))
i=$(( $i+1 ))
done
echo $s
exit语句
已经说过,不再讲
break与continue
语法与C语言中的break和continue类似,不再讲述
举例:
[root@jone ~]# cat break.sh
#!/bin/bash
for (( i=1;i<=10;i++ ))
do
if [ "$i" == 4 ]
then
continue
fi
echo "$i"
done