扬州网站建设哪家好WordPress反爬虫教程
 本章主要介绍如何使用bash写脚本。  
 
- 了解通配符
 - 了解变量
 - 了解返回值和数值运算
 
 grep的用法是“grep 关键字 file”,意思是从file中过滤出含有关键字的行。  
 
 
 例如,grep root /var/log/messages,意思是从/var/log/messages 中过滤出含有root  
 
 的行。这里很明确的是过滤含有“root”的行。  
 
 如果想在/var/log/messages 中过滤出含有IP地址的行呢?IP地址就是一类字符,例如,  
 
 1.1.1.1是一个IP,192.168.26.100也是一个IP,那么用什么能表示出来这一类字符呢?  
 
 不管是通配符还是正则表达式,都是为了模糊匹配,为了匹配某一类内容,而不是具体的  
 
 某个关键字。通配符一般用在shell语言中,正则表达式一般用在其他语言中。  
 
 不管是通配符还是正则表达式,主要是理解它们的元字符,然后用元字符来组合成我们想  
 
 要的那一类字符,本章主要讲解通配符的使用。  
 
 像我们平时说的张某某,这个某就是一个元字符,不是一个定值。指的是姓张,名字含有  
 
 2个字。张某某可能匹配到张二狗,也可能匹配到张阿猫,但是无法匹配到李阿三,也匹配  
 
 不了张三,因为张某某匹配的是姓名为3个字的,但是张三这个姓名只有2个字。  
 
 如果说有一个人姓“张”名“某”,那么需要匹配“张某”这个人,而不是要匹配张三、  
 
 张四,可以用张\某,某前加个“\”表示转义的意思。 
 
 
 
 
 22.1 通配符  
   通配符一般用在shell语言中,通配符中常见的元字符如下。  
  (1)[]:匹配一个字符,匹配的是出现在中括号中的字符。  
  (2)[abc]:匹配一个字符,且只能是a或b或c。  
  (3)[a-z]:“-”有特殊意义,表示“到”的意思,这里表示a~z,即匹配任一字母。  
  (4)[0-9]:表示匹配任一数字。  
  如果想去除含有特殊意义的字符,前面加“\”表示转义,即去除此字符的特殊意义。 (5)[a\-z]:这里的“-”就没有“到”的意思了,匹配的是“a”或“-”或“z”这三个  
  中的一个。  
  如果想表示“除了”的意思,则在第一个中括号后面加“!”或“^”。  
  (6)[!a-z]、[^a-z]:表示除字母外的其他字符。  
  (7)?:表示一个任意字符,这里强调是一个,不是0个也不是多个,但不能匹配表示隐藏  
  文件的点。  
  (8)*:表示任意多个任意字符,可以是0个,也可以是1个或多个,但不能匹配表示隐藏  
  文件的点。  
  练习:先创建目录xx并在目录中创建如下几个测试文件,命令如下。 
 [root@pp ~]# mkdir xx
[root@pp ~]# cd xx
[root@pp xx]# touch 1_aa aa11 Aa11 _aaa aa.txt f1aa u_12 flaa
[root@pp xx]# 
  找出首字符是字母、第二个字符是数字的文件,命令如下。  
 [root@pp xx]# ls [a-z][0-9]*
f1aa
[root@pp xx]# 
  找出首字符是字母、第二个字符不是数字的文件,命令如下。  
 [root@pp xx]# ls [a-z][^0-9]*
aa11  Aa11  aa.txt  flaa  u_12
[root@pp xx]# 
  如果要更精确,可以用如下元字符。  
  (1)[[:upper:]]:纯大写。  
  (2)[[:lower:]]:小写。  
  (3)[[:alpha:]]:字母。 (4)[[:alnum:]:字母和数字。  
  (5)[[:digit:]]:数字。 
   列出首字符是小写字母、第二个字符是数字的文件,命令如下。 
 [root@pp xx]# ls [[:lower:]][0-9]*
f1aa
[root@pp xx]# 
  列出首字符是大写字母、第二个字符是数字或字母的文件,命令如下。  
 [root@pp xx]# ls [[:upper:]][[:alnum:]]*
Aa11
[root@pp xx]# 
   22.2 变量  
  
 所谓变量,指的是可变的值,并非具体的值。例如,我自己嘴中发出的“我”,指的是我  
  自己,张三嘴中发出的“我”,指的是张三,那么这个“我”就是一个变量。  
  变量可以分为本地变量、环境变量、位置变量和预定义变量。 
   22.2.1 本地变量  
  定义本地变量的格式如下。 
 1 变量名=值  定义变量有以下几点需要注意。  
  (1)变量名可以包含_、数字、大小写字母,但不能以数字开头。  
  (2)“=”两边不要有空格。  
  (3)“值”如果含有空格,要使用单引号''或双引号""引起来。  
  (4)定义变量时,变量名前是不需要加$的,引用变量时需要在变量名前加$。  
  本章实验都放在~/yy中练习,命令如下。  
 [root@pp ~]# mkdir yy ; cd yy
[root@pp yy]# 
  下面开始练习定义变量,命令如下。 
 [root@pp yy]# 1aa=123
bash: 1aa=123: 未找到命令..  这里定义变量不正确,因为变量名不能以数字开头,这里定义变量不正确,因为变量名不能以数字开头 
   这里正确地定义了一个变量。  
  在使用本地变量时,变量名前需要加$,命令如下。 
 [root@pp yy]# aa=123
[root@pp yy]# echo $aa
123
[root@pp yy]# 
  本地变量的特点是只能影响当前shell,不能影响子shell。 
 [root@pp yy]# echo $aa
123
[root@pp yy]# echo $$
3070
[root@pp yy]# 
  当前shell的PID是3070。下面打开一个子shell。 
 [root@pp yy]# bash
[root@pp yy]# echo $$
3372
[root@pp yy]# 
  这个子shell 的PID是3372。 
  
 可以看到,没有aa变量。 
  
[root@pp yy]# echo $aa[root@pp yy]# exit
[root@pp yy]# echo $aa
123
[root@pp yy]# 
  再次退回到原来的bash,又有了aa变量,情形如图 
 
  定义变量除刚才显式的定义外,还可以使用如下两  
  种方法。  
  方法1:把一个命令的结果赋值给一个变量,这个  
  变量要使用$()括起来,或者用反引号“引起来。这里是反引号,与波浪号~是同--个键,不是  
  单引号。  
  例如,定义一个名称是ip的变量,对应的值是ens160的IP,命令如下。 
 [root@pp yy]# ip=$(ifconfig ens160 | awk '/inet /{print $2}')
[root@pp yy]# echo $ip
192.168.248.45
[root@pp yy]# 
  方法2:通过read命令来获取变量。  
  read的用法如下。  
 1 read ‐p "提示信息" 变量  当遇到read命令时,系统会等待用户输入,用户所输入的值会赋值给read后面的变量,  
  命令如下。 
 [root@pp yy]# read -p "请输入你的名字" aa
请输入你的名字iu
[root@pp yy]# echo $aa
iu
[root@pp yy]# 
  当执行read这条命令时,系统会提示用户输人一些内容,所输入的内容会赋值给aa变  
  量。这里我们输入的是 tom,所以打印aa变量时,看到的值是tom。  
  这样的用法比较适合写需要和用户交互的脚本。  
  22.2.2 环境变量  
  
 定义环境变量的注意点和本地变量是一样的。在定义环境变量时,前面加上export 即可,  
  命令如下。 
 [root@pp yy]# export bb=123
[root@pp yy]# 
  要想查看所有的环境变量,可以执行env命令。  
  环境变量的特点是可以影响子shell,这里强调的是子shell,不能影响父shell。 
  [root@pp yy]# echo $$
3070
[root@pp yy]# echo $bb
123
[root@pp yy]# 
  当前shell的PID是3828,里面有一个环境变量 bb。 
 [root@pp yy]#  bash
[root@pp yy]# echo $$
3828
[root@pp yy]# echo $bb
123
[root@pp yy]# 
  打开一个子shell,里面可以看到bb变量的值,说明环境变量已经影响到  
  子shell 了。 
  在子 shell中重新给bb赋值为456,然后退回到父shell。  
 [root@pp yy]# export bb=456
[root@pp yy]# exit
exit
[root@pp yy]# echo $bb
123
[root@pp yy]# 
  可以看到,在父shell 中,bb的值仍然是123,说明在子shell 中定义的变量不会影响到父  
  shell,如图22-2所示。 
 
  系统中默认已经存在很多个变量,如下所示。  
  (1)UID:表示当前用户的uid。  
  (2)USER:表示当前用户名。  
  (3)HOME:表示当前用户的家目录。 分别显示这些变量的值,命令如下。 
  [root@pp yy]# echo $UID
0
[root@pp yy]# echo $USER
root
[root@pp yy]# 
  22.2.3 位置变量和预定义变量  
  运行脚本时,有时后面是需要加上参数的。但是我们在写脚本时并不能预知后期在脚本后  
  面跟上什么参数,这时就能用到位置变量了,位置变量如下。  
  $0:表示脚本的名称。  
  $1:表示第1个参数。  
  $2:表示第2个参数。  
  ...... ${10}:表示第10个参数。  
  ......  
  这里$后面的数字如果不是个位数,则要用{}括起来。  
  系统中还内置了一些预定义变量。  
  $#:表示参数的个数。  
  $*:表示所有的参数。  
  例1:写一个带参数的脚本,内容如下。 
 [root@pp yy]# cat scl.yaml 
#/bin/bash
echo "这是我第一个脚本,脚本名称是 $0"
echo "第 1 个参数是:$1"
echo "第 2 个参数是:$2"
echo "第 3 个参数是:$3"
echo "此脚本一共有 $# 个参数,它们分别是:$*"
[root@pp yy]# 
  给这个脚本加上可执行权限,并加参数运行,命令如下。  
 [root@pp yy]# chmod +x scl.yaml 
[root@pp yy]# ./scl.yaml tom bob mary
这是我第一个脚本,脚本名称是 ./scl.yaml
第 1 个参数是:tom
第 2 个参数是:bob
第 3 个参数是:mary
此脚本一共有 3 个参数,它们分别是:tom bob mary
[root@pp yy]# 
  运行这个脚本时,共指定了3个参数:tom、bob、mary,它们分别赋值给了  
  $1、$2、$3。这里S#被自动赋值为3,因为总共有3个参数,所有的参数被赋值给$*。 
  22.3 返回值  
   执行某命令之后,结果不是正确的就是错误的。命令正确执行了,返回值为0,如果没有  
  正确执行则返回值为非零。返回值为非零,不一定是语法错误,执行结果如果有“否定”的  
  意思,返回值也为非零。例如, ping 192.168.26.3,语法没有错误,但是没有ping通,返回值  
  也为非零。  
  返回值记录在$?中,且$?只记录刚刚执行过命令的返回值。因为$?的值会被新执行命令  
  的返回值覆盖。  
  练习:先执行一个 xxx命令,命令如下。  
 [root@pp yy]# xxx
bash: xxx: 未找到命令...
[root@pp yy]# echo $?
127
[root@pp yy]# echo $?
0
[root@pp yy]# 
  先执行一个xxx命令,这个命令是错误的命令,$?记录的是刚刚执行过xxx命令的返回值。  
  所以,查看$?的值是127,是一个非零的值。再次查看$?的值时,却变成了0,因为这个$?  
  记录的不再是xxx命令的返回值,而是它前面执行过的echo $?命令的返回值。 逻辑上“否定”的意思也是可以体现出来的。例如,下面的例子。 
 [root@pp yy]# grep ^root /etc/passwd
root:x:0:0:root:/root:/bin/bash
[root@pp yy]# echo $?
0
[root@pp yy]# 
  这里在/etc/passwd过滤行开头为root的行,结果找到了,所以返回值为0。  
 [root@pp yy]# grep ^rootxxx /etc/passwd
[root@pp yy]# echo $?
1
[root@pp yy]# 
  这里在/etc/passwd过滤行开头为rootxxx的行,结果没有找到,即使语法没有错误,但  
  是逻辑上有“否定”的意思,所以返回值为非零。 
  
 22.4数值运算  
  在写脚本时,有时我们经常要做一些数学运算。数学运算的符号如下。  
  (1)+:表示加。  
  (2)-:表示减。  
  (3)*:表示乘。  
  (4)/:表示除。  
  (5)**:表示次方。 
  
 进行数学运算的表达式有$(())、$[]、let等,命令如下。 
 [root@pp yy]# echo $((2+3))
5
[root@pp yy]# 
  其中$(O)和$[]的用法是一样的,如果不用这样的表达式,看如下代码。 
 [root@pp yy]# echo 2**3
2**3
[root@pp yy]# 
  可以实现定义aa为整数类型,然后再做数学运算,命令如下。 
 [root@pp yy]# declare -i aa
[root@pp yy]# aa=1+2
[root@pp yy]# echo $aa
3
[root@pp yy]# 
  首先declare -i aa把aa定义为一个整数,所以1+2等于3,然后赋值给aa.所以aa的值为3。  
  以上表达式不能求得小数,如果要得到小数需要使用 bc 命令,用法如下。 
 1 echo "scale=N ; 算法 | bc"  这里N是一个数字,表示小数点后面保留几位。  
  计算2/3,小数点后面保留3位,命令如下。 
 [root@pp yy]# echo "scale=3 ; 2/3" | bc
.666
[root@pp yy]# 
  这里得到的结果是0.666,整数部分的0没有显示。  
  计算7/6,小数点后面保留3位,命令如下。 
 [root@pp yy]# echo "scale=3 ; 7/6" | bc
1.166
[root@pp yy]# 
  