11Linux之shell高级

BamB00 2019-11-26 00:00:00
Categories: Tags:

0x01 正则概述

正则是用来再文件中匹配符合条件的字符串。

通配符用来匹配符合条件的文件名。

正则表达式的分类

  1. 基本的正则表达式(Basic Regular Expression 又叫Basic RegEx 简称BREs)
  2. 扩展的正则表达式(Extended Regular Expression 又叫Extended RegEx 简称EREs)
  3. Perl的正则表达式(Perl Regular Expression 又叫Perl RegEx 简称PREs)
命令 支持选项
grep,aws,sed 正则表达式
ls,find,cp 通配符

0x02 基础正则表达式

基本正则表达式(BRE)和扩展正则表达式(ERE)

正则表达式 描述 示例 Basic RegEx Extended RegEx Python RegEx Perl regEx
\ 转义符,将特殊字符进行转义,忽略其特殊意义 a.b匹配a.b,但不能匹配ajb,.被转义为特殊意义 \ \ \ \
^ 匹配行首,awk中,^则是匹配字符串的开始 ^tux匹配以tux开头的行 ^ ^ ^ ^
$ 匹配行尾,awk中,$则是匹配字符串的结尾 tux$匹配以tux结尾的行 $ $ $ $
. 匹配除换行符\n之外的任意单个字符,awk则中可以 ab.匹配abc或bad,不可匹配abcd或abde,只能匹配单字符 . . . . .
[] 匹配包含在[字符]之中的任意一个字符 coo[kl]可以匹配cook或cool [] [] [] []
[^] 匹配[^字符]之外的任意一个字符 123[^45]不可以匹配1234或1235,1236、1237都可以 [^] [^] [^] [^]
[-] 匹配[]中指定范围内的任意一个字符,要写成递增 [0-9]可以匹配1、2或3等其中任意一个数字 [-] [-] [-] [-]
? 匹配之前的项1次或者0次 colou?r可以匹配color或者colour,不能匹配colouur 不支持 ? ? ?

注意事项:

  1. 任何符号+*匹配所有内容例如 :grep "a*" text.txt 因为*包含0此,所以不管有没有a都包含。 正确的内匹配所有内容应该是grep ".*" test.txt
  2. 匹配空白行 ^$
  3. {}要使用转义符如\{n\}

0x03 字符串截取和替换命令

0x031 cut列提取命令

#cut [选项] 文件名
选项:
    -f 列号 : 提取第几列
    -d 分隔符 : 按照指定分隔符分割列
    -c 字符串范围 : 不依赖分隔符来风恶劣,。而是通过字符范围(行首为0)来进行提取。"n-"表示从第n个字符到行尾:"n-m"从第n个字符到第m个字符: "-m" 表示从第1个字符到第m个字符

例子

#cut -f 2,3 test.txt
#cut -d ":" test.txt

0x032 printf 格式化输出

printf [format] [文本1] [文本2] ..
#printf '%s' $(cat test.txt)
  1. 其与print命令的最大不同是,printf需要指定format;

  2. format用于指定后面的每个item的输出格式;

  3. printf语句不会自动打印换行符;\n

#printf '%s\t %s\t \n' $(cat test.txt) 

常用格式替换符

代码 格式化意义
%s 字符串
%f 浮点格式
%c ASCII字符,即显示对应参数的第一个字符
%d,%i 十进制整数
%o 八进制值
%u 不带正负号的十进制值
%x 十六进制值(a-f)
%X 十六进制值(A-F)
%% 表示%本身

常用转义字符

代码 格式化意义
\a 警告字符,通常为ASCII的BEL字符
\b 后退
\f 换页
\n 换行
\r 回车
\t 水平制表符
\v 垂直制表符
\ 表示\本身

不常用的转化

awk用法详解

0x032 awk编程

awk拥有完整的编程语言

这里只写基本使用

#awk '条件1{动作} 条件2{动作}.....' 文件名
条件(Pattern):
    一般使用关系表达式作为条件。这些关系表达式非常多,具体参考表12-3所示,例如:
    x>10 判断变量 x是否大于10
    x==y 判断变量x是否等于变量y
    a ~ b 判断字符串a中是否包含b表达式的子字符串
    a !~ b 判断字符串a中是否不包含b表达式的子字符串d
动作(Action):
    格式化输出
    流程语句控制

awk的条件

运算符 描述
= += -= *= /= %= ^= **= 赋值
?: C条件表达式
&& 逻辑与
~ ~! 匹 配正则表达式和不匹配正则表达式
< <= > >= != == 关 系运算符
空格 连接

awk内置变量

变 量 描述
$n 当前记录的第n个字段,字段间由 FS分隔。
$0 完整的输入记录。
ARGC 命 令行参数的数目。
ARGIND 命令行中当前文件的位置(从0开始算)。
ARGV 包 含命令行参数的数组。
CONVFMT 数字转换格式(默认值为%.6g)
ENVIRON 环 境变量关联数组。
ERRNO 最后一个系统错误的描述。
FIELDWIDTHS 字 段宽度列表(用空格键分隔)。
FILENAME 当前文件名。
FNR 同 NR,但相对于当前文件。
FS 字段分隔符(默认是任何空格)。
IGNORECASE 如 果为真,则进行忽略大小写的匹配。
NF 当前记录中的字段数。
NR 当 前记录数。
OFMT 数字的输出格式(默认值是%.6g)。
OFS 输 出字段分隔符(默认值是一个空格)。
ORS 输出记录分隔符(默认值是一个换行符)。
RLENGTH 由 match函数所匹配的字符串的长度。
RS 记录分隔符(默认是一个换行符)。
RSTART 由 match函数所匹配的字符串的第一个位置。
SUBSEP 数组下标分隔符(默认值是\034)。

一般内置变量只常用$0,$n,NF,NR,FS

0x033 sed 命令

在程序中要修改数据只能用sed

#sed 选项  '动作' 文件名
选项:
    -n :一般sed命令会把所有数据都输出到屏幕,如果加入此选项,会把经过sed命令处理的行输出到屏幕
    -e : 允许输入数据应用多条sed命令编辑
    -f 脚本名文件名 : 从sed脚本中读入sed操作。和awk命令的-f非常类似
    -r : 在sed中支持扩展正则表达式
    -i : 用sed的修改结果直接修改读取数据的文件,而不是由屏幕输出
动作:
    a \ : 追加。在当前行后添加一行或多行,除最后一行外,每行末尾需要用"\"代表数据未完结
    c \ : 行替换,用c后面的字符串替换源数据行,替换多行时,除最后一行外,每行末尾需要用"\"代表数据未完
    i \ : 插入,在当期行前插入一行或多行。插入多行时,除最后一行外,每行末尾需要用"\"代表数据未完
    d : 删除,删除指定的行
    p : 打印,输出指定的行
    s : 字串替换,用一个字符串替换另一个字符串。格式为 "行方位 s/就字符串/新字符串/g"

例如

#set  '2a 1111111111111111111' test.txt        a在后面i在前面
#set -e '3d ; 4d' text.txt  #执行删除第三第四行数据
#set 's/new/old/g' txest.txt #全文替换

0x034 sort

sort:排序

#sort [选项] 文件名
选项:
    -f : 忽略大小写
    -b : 忽略每行前面的空白部分
    -n : 以数值型进行排序,默认使用字符串型排序
    -r : 反向排序
    -u : 删除重复行.就是Uniq命令
    -t : 指定分隔符,默认是分隔符是制表符

例如

# sort -r -t ':' -n -k '3,3' /etc/passwd

0x035 uniq

用来取消重复的行命令,其实和”sour -u”一样。命令格式如下:

# uniq [选项] 文件名
选项:
    -i : 忽略大小写

0x036 wc

用来统计的

# wc [选项] 文件名
选项:
    -l : 只统计行数
    -w : 只统计单词数
    -m : 只统计字符数

0x04 条件判断

0x041 按照文件类型进行判断

测试选项 作用
-b 文件 判断该文件是否存在,并且是否为块设备文件
-c 文件 判断该文件是否存在,并且是否为字符设备文件
-d 文件 判断该文件是否存在,并且是否为目录文件
-e 文件 判断该文件是否存在
-f 文件 判断该文件是否存在,并且是否为普通文件
-L 文件 判断该文件是否存在,并且是否为符号链接文件
-p 文件 判断该文件是否存在,并且是否为管道文件
-s 文件 判断该文件是否存在,并且是否为空
-S 文件 判断该文件是否存在,并且是否为套接字文件

常用的-d,-e -f -L -s

使用方法有两种

# test -e ip.txt #方法一 
# [ -e ip.txt ] #方法二 常用    

例子

[ -d ip.txt ] && echo yes || echo no

0x042 按照文件权限进行判断

测试选项 作用
-r 文件 判断该文件是否存在,并且是否该文件拥有读权限
-w 文件 判断该文件是否存在,并且是否该文件拥有写权限
-x 文件 判断该文件是否存在,并且是否该文件拥有执行权限
-u 文件 判断该文件是否存在,并且是否该文件拥有SUID权限
-g 文件 判断该文件是否存在,并且是否该文件拥有SGID权限
-k 文件 判断该文件是否存在,并且是否该文件拥有SBit权限

使用方法同上,注意这个办法不能区分所属组所属者陌生人。所以只要任意一个用户拥有权限即可。如要细分写脚本单独提取相对应的权限。

0x043 两个文件之间进行比较

测试选项 作用
文件1 -nt 文件2 判断文件1d的修改时间是否比文件2的新
文件1 -ot 文件2 判断文件1d的修改时间是否比文件2的旧
文件1 -ef 文件2 判断文件1是否和文件2的Inode号一致,可以裂解为两个文件是否为同一个文件。这个判断硬链接是个很好的办法。

0x044 两个整数之间比较

测试选项 作用
整数1 -eq 整数2 判断整数1是否和整数2相等
整数1 -ne 整数2 判断整数1是否和整数2不相等
整数1 -gt 整数2 判断整数1是否大于整数2
整数1 -lt 整数2 判断整数1是否小于整数2
整数1 -ge 整数2 判断整数1是否大于等于整数2
整数1 -le 整数2 判断整数1是否小于等于整数2

背诵方法 Equal 相等 greater大于 less小于

0x045 字符判断

测试选项 作用
-z 字符串 判断字符串是否为空
-n 字符串 判断字符串是否为非空
字符串1 == 字符串2 判断字符串1是否和字符串2相等
字符串1 != 字符串2 判断字符串1是否不等于字符串2

这里==和!=可以用于判断数值是否相等因为数值的二进制码也是一样的。但是判断不了大小

0x046 条件判断

测试选项 作用
判断1 -a 判断2 逻辑与,判断1和判断2都成立,则真 a=and
判断1 -o 判断2 逻辑或,,判断1和判断一只有一个成立,则真 o=or
!判断 逻辑非,结果取反 !=not

例子

aa=40
[ -n "$aa" -a "$aa" -gt "30" ] && echo yes || echo no

0x05 流程控制

0x051 if条件语句

语法如下

if [条件判断式]
    then
        程序
fi

例子 tset.sh

#判断分区使用率是否大于80%
#!/bin/bash
aa=$(df -h | grep /dev/mapper/centos-root | awk '{print $5}' | cut -d "%" -f 1)

if [ "$aa" -ge 5 ]
         then
                 echo "大于百分之5"
fi

0x052 双分支if条件

语法如下

if [条件判断式]
    then 
        程序1
    else
        程序2
fi

例子

服务器有时候会宕机。如果我们对服务器监控不好,就会造成服务宕机,而管理员却不知道的情况,这时我们写一个脚本来监听本机的服务,如果服务器宕机就重启。例如Apache服务

#!/bin/bash
#找出端口号
port=$( nmap 192.168.205.128 | grep "tcp" | awk '$2=="open" && $3=="ssh"' )

if [ "$port" == "" ]
        then
                echo "httpd is down , must restart"
                service httpd restart >> /dev/null
         else
                echo "httpd is ok"
fi

0x053 多分枝

if [条件1]
    then
        程序
elif [条件2]
    then
        程序
.....
else 
    当所有条件不满足时执行程序
fi

例子test3.sh判断用户输入的是什么文件。

#!/bin/bash

#接收键盘输入,并赋予变量file
read -p "Please input a filename: " file

#判断是否为空
if [ -z $fiel ]
        then
                echo "Error emply input"
                exit 1
#判断是否文件
elif [ ! -e $file"]
        then
                echo "Error input date not file"
                exit 1
elif [ -f $file ]
        then
                echo "$file is a regulare file!"
elif [ -d $file ]
        then
                echo "$file is a directory!"
else
        echo ""$file is an other file!"
fi

0x054 多分支case条件语句

case $变量名 in
    "值1")
        程序1
    "值2")
        程序2
        ;;
    .....
    *)
        不满足条件执行程序
        ;;
esac

0x055 for循环

第一种写法

for 变量 in 值1 值2 值3.....
    do
        程序
    done

第二种写法

for(( i=1;i<=100;i=i+1))
    do
        s=$(( $s+%i))
    done
echo "1+2+。。。100 : $s"

0x056 while循环

while [ 条件判断式 ]
    do
        程序
        条件改动
    done

注意while的判断不会自增和自减。所以要条件改动

0x057 until循环

until循环和while循环相反,until是条件不满足循环

until [ 条件判断式 ]
    do
        程序
    done

0x06 特殊流程控制语句

0x061 exit

exit [返回值]

exit常用的表示值

意义
0 正常执行
1 报错

这个值可以自定义设置这样在写庞大的脚本时快速找到错误点

0x062 break和continue

break和continue普通编程一样。

0x07 加减乘除完整版

#!/bin/bash

#赋予两个变量和输入计算符号
read -t 30 -p "Please input num1: " num1
read -t 30 -p "Please input num2: " num2
read -t 30 -p "Please input operater: " ope


#判断num1,num2以及ope是否为空
if [ -n "$num1" -a -n "$num2" -a -n "$ope" ]
        then
                #把test1中数字替换为空。如果完后test1为空证明num1为纯数字数字
                test1=$( echo $num1 | sed '/[0-9]//g' )
                test2=$( echo $num2 | sed '/[0-9]//g' )
        #判断test1和test2为空则输入为纯数字
        if [ -z "$test1" -a -z "$test2" ]
                then
                        case "$ope" in                               
                         "+")
                                        value=$(( $num1 + $num2 ))
                                        ;;
                        "-")
                                        value=$(( $num1 - $num2 ))
                                        ;;
                           "*")
                                        value=$(( $num1 * $num2 ))
                                        ;;
                        "/")
                                        value=$(( $num1 / $num2 ))
                                        ;;
                        *)
                                echo "Error, Please enter a valid symbol"
                                ;;
                        esac
        else
                echo "Please enter a valid value"
                exit 11
        fi
fi

echo " $num1 $ope $num2 : $value"

0x08 判断合法IP地址

#!/bin/bash

#正则提取范围在 0-999.0-999.0-999.0-999范围的IP地址
grep "^[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}" /root/sh/ip.txt > /root/sh/ip_test1.txt

#统计test1中有几行IP地址
line=$(wc -l /root/sh/ip_tset1.txt | awk '{print $1}')
#清除数据
echo " "> /root/sh/ip_test.txt

for((i=1;i<=$line;i=i+1))
    do
        cat /root/sh/ip_test1.txt | awk'NR=='$i'{print}' > /root/sh/ip-test2.txt
        a=$(cat /root/sh/ip_test2.txt | cut -d '.' -f1 )
        b=$(cat /root/sh/ip_test2.txt | cut -d '.' -f2 )
        c=$(cat /root/sh/ip_test2.txt | cut -d '.' -f3 )
        d=$(cat /root/sh/ip_test2.txt | cut -d '.' -f4 )
        如果IP值小于1或大于255退出
        if ["$a" -lt 1 -o "$a" -gt 255]
            then 
                continue
        fi
        
        if ["$b" -lt 0 -o "$a" -gt 255]
            then 
                continue
        fi
        
        if ["$c" -lt 1 -o "$a" -gt 255]
            then 
                continue
        fi
        
        if ["$d" -lt 1 -o "$a" -gt 255]
            then 
                continue
        fi
        #判断玩写入文件
        cat/root/sh/ip_test2.txt >> /root/sh/ip_test.txt
    done
#清理临时文件
rm -rf /root/sh/ip_test1.txt
rm -rf /root/sh/ip_test2.txt

0x09 批量添加指定数量的用户

#!/bin/bash

read -p "Please input user name: " -t 30 name
read -p "Please input number of users" -t 30 num
read -p "Please input password of users" -t 30 pass
#判断三个变量都为非空
if [ !z "$name" -a ! -z "$num" -a -z "$pass"]
    then
        #判断Num为数字
        y=$(echo $num | sed 's/[0-9]//g')
        if [-z "$y"]
            then
                for((i=i;i<=$num;i=i+1))
                    do
                        #添加用户
                        /usr/sbin/useradd $name$i &>/dev/null
                        #设定密码
                        echo $pass | /usr/bin/passwd --stdin $name$i &>/dev/null
                        #强制用户登录后修改密码
                        chage -d 0 $name$i &>/dev/null
                    done
                    
        fi
fi                        

0x10 批量删除用户

#!/bin/bash

user=$( cat /etc/passwd | grep "/bin/bash" | grep -v "root" | cut -d ":" f1 )
for i in $user
    do
        userdel -r $i
    done