正规表示法用在非常多地方!熟悉正规表示法好处多多!因为其他编程语言也会用到这玩意儿喔!
谈完了指令列的 bash shell 的操作,再来得要思考一下,如果管理员有一堆指令要循序进行,且这些指令可能具有相依性 (例如判断式), 或者是管理员需要写一些让用户『交互』的脚本时,应该如何处理?这时就得要通过 bash 的 shell script (程序化脚本) 来进行了。 此外,很多时候我们需要进行数据的截取,这时好用的正规表示法就得要派上用场了!
用户在操作电子邮件时,常常会发现到许多邮件被丢到垃圾桶或者是被判定为病毒邮件,这些判定的方式,很多就是通过『正规表示法』来处理的! 正规表示法 (Regular Expression) 就是处理字符串的方法,他是以行为单位来进行字符串的处理行为,正规表示法通过一些特殊符号的辅助, 可以让用户轻易的达到『搜索/删除/取代』某特定字符串的处理程序!
由于正规表示法牵涉到数据的截取,因此读者们先了解一下最简单的数据截取指令: grep 的高端用法。例如,找出 /etc/passwd 当中, 含有 student 的那行,且列出行号:
[student@localhost ~]$ grep -n student /etc/passwd 44:student:x:1000:1000:student:/home/student:/bin/bash
读者们会看到输出的信息中,最前面会多出一个行号的信息,就可以让用户知道该信息来自文件的那一行这样。 另外,当用户有观察开机流程所产生的信息时,例如想要查找开机过程产生的问题等等,可以使用 dmesg 这个指令。 只是这个指令输出的信息量非常庞大。若用户仅须知道某张网络卡的相关信息,那该如何处理呢? 先让我们来查找一下网络卡的代号:
# 单纯使用 dmesg 的情况下,数据量相当庞大 [student@localhost ~]$ dmesg ...... [ 9.775271] virbr0: port 1(virbr0-nic) entered listening state [ 9.839811] virbr0: port 1(virbr0-nic) entered disabled state [ 10.359755] f 4026531860#85: failed to wait on release 20 after... [ 11.638731] snd_hda_intel 0000:00:06.0: Invalid position buffer... # 使用底下的方法可以找到网络卡的代号 [student@localhost ~]$ ip link show 1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN mode DEFAULT group default qlen 1000 link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00 2: ens3: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP mode DEFAULT group default qlen 1000 link/ether 52:54:00:85:b1:54 brd ff:ff:ff:ff:ff:ff 3: virbr0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN mode DEFAULT group default qlen 1000 link/ether 52:54:00:b0:2f:5d brd ff:ff:ff:ff:ff:ff 4: virbr0-nic: <BROADCAST,MULTICAST> mtu 1500 qdisc fq_codel master virbr0 state DOWN mode DEFAULT group default qlen 1000 link/ether 52:54:00:b0:2f:5d brd ff:ff:ff:ff:ff:ff
上面输出的 ens3 就是网卡代号,而 lo 与 virbr0 等则是内部循环测试网卡与虚拟机的桥接器,那个可以暂时略过不理。 现在,让我们从 dmesg 的开机消息中,找出网络卡相关的消息吧:
[student@localhost ~]$ dmesg | grep -n -i ens3
552:[ 1.853119] virtio_net virtio0 ens3: renamed from eth0
616:[ 7.911858] IPv6: ADDRCONF(NETDEV_UP): ens3: link is not ready
大概在 616 行是比较重要的项目。那如果我们还需要知道该行之前 (before) 的 4 行以及之后 (after) 的 3 行, 以了解这行前后文的话,则可以这样处理:
[student@localhost ~]$ dmesg | grep -n -A 3 -B 4 -i ens3 612-[ 6.424222] RPC: Registered tcp transport module. 613-[ 6.424223] RPC: Registered tcp NFSv4.1 backchannel transport module. 614-[ 7.577042] f 4026531841#1: failed to wait on release 1 after spincount 301 615-[ 7.905917] bridge: filtering via arp/ip/ip6tables is no longer available by default. Update your scripts to load br_netfilter if you need this. 616:[ 7.911858] IPv6: ADDRCONF(NETDEV_UP): ens3: link is not ready <==以这行为基准 617-[ 7.926902] tun: Universal TUN/TAP device driver, 1.6 618-[ 7.930979] virbr0: port 1(virbr0-nic) entered blocking state 619-[ 7.930981] virbr0: port 1(virbr0-nic) entered disabled state
正规表示法既然是通过一些字符来作为数据截取的判断,那么有哪些惯用的符号呢?大概有底下这些基本的符号:
RE 字符 | 意义与范例 |
^word | 意义:待搜索的字符串(word)在行首! 范例:搜索行首为『 # 』开始的那一行,并列出行号 grep -n '^#' regular_express.txt |
word$ | 意义:待搜索的字符串(word)在行尾! 范例:将行尾为『 ! 』的那一行打印出来,并列出行号 grep -n '!$' regular_express.txt |
. | 意义:代表『一定有一个任意字符』的字符! 范例:搜索的字符串可以是 (eve) (eae) (eee) (e e), 但不能仅有 (ee) !亦即 e 与 e 中间『一定』仅有一个字符,而空白字符也是字符! grep -n 'e.e' regular_express.txt |
\ | 意义:跳脱字符,将特殊符号的特殊意义去除! 范例:搜索含有单引号『 ' 』的那一行! grep -n \' regular_express.txt |
* | 意义:重复零个到无穷多个的前一个 RE 字符 范例:找出含有 (es) (ess) (esss) 等等的字符串,注意,因为 * 可以是 0 个,所以 es 也是符合带搜索字符串。另外,因为 * 为重复『前一个 RE 字符』的符号, 因此,在 * 之前必须要紧接着一个 RE 字符喔!例如任意字符则为 『.*』 ! grep -n 'ess*' regular_express.txt |
[list] | 意义:字符集合的 RE 字符,里面列出想要截取的字符! 范例:搜索含有 (gl) 或 (gd) 的那一行,需要特别留意的是,在 [] 当中『谨代表一个待搜索的字符』, 例如『 a[afl]y 』代表搜索的字符串可以是 aay, afy, aly 即 [afl] 代表 a 或 f 或 l 的意思! grep -n 'g[ld]' regular_express.txt |
[n1-n2] | 意义:字符集合的 RE 字符,里面列出想要截取的字符范围! 范例:搜索含有任意数字的那一行!需特别留意,在字符集合 [] 中的减号 - 是有特殊意义的,他代表两个字符之间的所有连续字符!但这个连续与否与 ASCII 编码有关,因此,你的编码需要设置正确(在 bash 当中,需要确定 LANG 与 LANGUAGE 的变量是否正确!) 例如所有大写字符则为 [A-Z] grep -n '[A-Z]' regular_express.txt |
[^list] | 意义:字符集合的 RE 字符,里面列出不要的字符串或范围! 范例:搜索的字符串可以是 (oog) (ood) 但不能是 (oot) ,那个 ^ 在 [] 内时,代表的意义是『反向选择』的意思。 例如,我不要大写字符,则为 [^A-Z]。但是,需要特别注意的是,如果以 grep -n [^A-Z] regular_express.txt 来搜索,却发现该文件内的所有行都被列出,为什么?因为这个 [^A-Z] 是『非大写字符』的意思, 因为每一行均有非大写字符,例如第一行的 "Open Source" 就有 p,e,n,o.... 等等的小写字 grep -n 'oo[^t]' regular_express.txt |
\{n,m\} | 意义:连续 n 到 m 个的『前一个 RE 字符』 意义:若为 \{n\} 则是连续 n 个的前一个 RE 字符, 意义:若是 \{n,\} 则是连续 n 个以上的前一个 RE 字符! 范例:在 g 与 g 之间有 2 个到 3 个的 o 存在的字符串,亦即 (goog)(gooog) grep -n 'go\{2,3\}g' regular_express.txt |
另外,由于字符截取通常会有大小写、数字、特殊字符等等的差异,因此我们也能够使用如下的符号来代表某些特殊字符:
特殊符号 | 代表意义 |
[:alnum:] | 代表英文大小写字符及数字,亦即 0-9, A-Z, a-z |
[:alpha:] | 代表任何英文大小写字符,亦即 A-Z, a-z |
[:blank:] | 代表空白键与 [Tab] 按键两者 |
[:cntrl:] | 代表键盘上面的控制按键,亦即包括 CR, LF, Tab, Del.. 等等 |
[:digit:] | 代表数字而已,亦即 0-9 |
[:graph:] | 除了空白字符 (空白键与 [Tab] 按键) 外的其他所有按键 |
[:lower:] | 代表小写字符,亦即 a-z |
[:print:] | 代表任何可以被打印出来的字符 |
[:punct:] | 代表标点符号 (punctuation symbol),亦即:" ' ? ! ; : # $... |
[:upper:] | 代表大写字符,亦即 A-Z |
[:space:] | 任何会产生空白的字符,包括空白键, [Tab], CR 等等 |
[:xdigit:] | 代表 16 进位的数字类型,因此包括: 0-9, A-F, a-f 的数字与字符 |
请操作者进行如下的例题来处理相关任务:
sed 也是支持正规表示法的一项工具软件,具有很多很好用的功能在内!过去我们曾经使用过 ifconfig 与 awk 来找到 IP , 现在让我们使用 sed 来处理 IP 的设置。最基础的 sed 功能为取代,如下所示:
[student@localhost ~]$ sed 's/旧字符串/新字符串/g' 文件内容
用户只要替换『新旧字符串』内容,即可处理相关的字符串修订。现在让我们来处理 IP 的截取。使用 ifconfig ens3 来输出网络数据, 之后以 grep 取出 inet 那一行 (注意: ens3 请依据你的系统网卡来调整):
[student@localhost ~]$ ifconfig ens3 | grep 'inet[[:space:]]'
inet 172.16.5.237 netmask 255.255.0.0 broadcast 172.16.255.255
使用 sed 取代开头到 inet 空白的项目:
[student@localhost ~]$ ifconfig ens3 | grep 'inet[[:space:]]' | \ > sed 's/^.*inet[[:space:]]//g' 172.16.5.237 netmask 255.255.0.0 broadcast 172.16.255.255
再接着取消空白netmask 之后的消息
[student@localhost ~]$ ifconfig ens3 | grep 'inet[[:space:]]' | \ > sed 's/^.*inet[[:space:]]//g' | \ > sed 's/[[:space:]]*netmask.*$//g' 172.16.5.237
除了替换数据之外,sed 还可以截取出特定的关键行数,例如只想要取出 10-15 行的 /etc/passwd 内容时,可以这样做:
[student@localhost ~]$ cat -n /etc/passwd | sed -n '10,15p'
上面这个动作在处理一些脚本化程序时,相当有帮助!而如果想要直接修改文件内容时,例如想要将 .bashrc 内的 function 改成大写时, 也可以这样做:
[student@localhost ~]$ sed 's/function/FUNCTION/g' .bashrc ....... # User specific aliases and FUNCTIONs >==这里会变大写 [student@localhost ~]$ sed -i 's/function/FUNCTION/g' .bashrc
加上 -i 选项后,该改变直接写入文件,且不会在屏幕上输出了!因此使用上需要特别注意!
shell script 对管理员来说,是一项非常好用的工具!请读者们一定要自己手动设计过一次相关的脚本程序, 而且能够针对自己管理的服务器进行一些例行工作的优化,才会更有感觉。
shell script 的撰写其实没有很难,基本上需要注意到:
至于 shell script 的运行,例如有名为 /home/student/shell.sh 的 script 时,可以用底下的方法:
底下我们将使用 student 的身份,并在 ~/bin 底下创建多个 shell script 来作为练习。首先,如果操作者运行 myid.sh 时, 系统会输出这个帐号的 id 指令输出消息,并且输出用户的家目录 (${HOME})、以及历史命令纪录笔数 (${HISTSIZE}), 最后列出所有的命令别名 (alias) 时,我们可以这样做:
上述的结果一项一项撰写成为 myid.sh 的内容如下:
[student@localhost ~]$ mkdir bin [student@localhost ~]$ cd bin [student@localhost bin]$ vim myid.sh #!/bin/bash # This script will use id, echo to show account's messages # write by VBird 2016/04/27 echo "This script will show your accout messages." echo "The 'id' command output is: " id echo "your user's home is: ${HOME}" echo "your history record: ${HISTSIZE}" echo "your command aliases: " alias echo "your home dir's filenames: " ll ~
之前曾经谈过进程的观察,且进程之间是有相依性的,因此可以使用 pstree 来观察进程的相依行为。 那么使用 shell script 时,他与当前的 shell 有无关系呢?底下举例来瞧瞧。如果你有一个如下的脚本, 该如何进入到该目录去?
[student@localhost ~]$ cd ~/bin [student@localhost bin]$ vim gototmp.sh #!/bin/bash # this shell script will take you togo /tmp directory. # VBird 2016/05/02 cd /tmp pwd [student@localhost bin]$ chmod a+x gototmp.sh
事实上,运行脚本有基本的两种方式:
上述的第二种就是通过 source 或 . 来处理的。现在,请使用『 source ~/bin/gototmp.sh 』指令, 再次查阅一下你的工作目录是否正确的进入到 /tmp 了?
[student@localhost bin]$ source gototmp.sh /tmp [student@localhost tmp]$ pwd /tmp
在第二堂课我们曾经使用过 bc 来计算数学的 pi,亦即使用『echo "scale=10; 4*a(1)" | bc -lq』来计算 pi。 而如果需要输出更正确的 pi 值,可以将 scale 的参数放大,例如『echo "scale=20; 4*a(1)" | bc -lq』来计算。 我们是否能够使用一个变量,让该变量带入脚本后,让用户可以与系统对谈呢?这时有两种基本的方法可以达到这个目的:
读者可以先理解 read 的用法:
[student@localhost ~]$ read -p 'Input your name: ' name1 Input your name: VBird Tsai [student@localhost ~]$ echo ${name1} VBird Tsai
亦即 read 会将用户输入的数据变成变量内容,之后就可以轻易的进行变量设置的任务。因此,若需要让用户与程序交互来输入 pi 的计算精确度, 可以写下如下的脚本:
[student@localhost ~]$ vim ~/bin/mypi.sh #!/bin/bash # Program: # User input a scale number to calculate pi number. # History: # 2015/07/16 VBird First release PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin export PATH echo -e "This program will calculate pi value. \n" echo -e "You should input a float number to calculate pi value.\n" read -p "The scale number (10~10000) ? " num echo -e "Starting calculate pi value. Be patient." time echo "scale=${num}; 4*a(1)" | bc -lq [student@localhost ~]$ chmod a+x ~/bin/mypi.sh [student@localhost ~]$ mypi.sh This program will calculate pi value. You should input a float number to calculate pi value. The scale number (10~10000) ? 50 Starting calculate pi value. Be patient. 3.14159265358979323846264338327950288419716939937508 real 0m0.001s user 0m0.000s sys 0m0.002s
此时,只要用户运行 mypi.sh ,就可以手动输入 10 到 10000 之间不等的数值,让系统直接进行运算工作!此外你得要注意, 在 echo 显示信息时,可以使用 \t, \n 等方法来处理断行、[tab] 按钮的样式~只是需要加上 -e 的选项才行!你可以『 man echo 』查找可用的变量!
[student@localhost ~]$ listcmd.sh This shell script will list your command's full path name and permissions. Please input a command name: ls -rwxr-xr-x. 1 root root 166448 5月 12 2019 /usr/bin/ls getfacl: Removing leading '/' from absolute path names # file: usr/bin/ls # owner: root # group: root user::rwx group::r-x other::r-x
在第 8 堂课的课程内容曾经短暂介绍过 shell 内有个名为 ${1} 的变量,即是 shell script 的外带参数。事实上,外带参数可以有多个, 相关的『数字变量』有底下的相关性:
/path/to/scriptname opt1 opt2 opt3 opt4
$0 $1 $2 $3 $4
运行的脚本文件名为 ${0} 这个变量,第一个接的参数就是 ${1}。所以,只要在 script 里面善用 ${1} ,就可以很简单的立即下达某些指令功能了! 除了这些数字的变量之外,尚有底下这些常见的变量可以在 shell script 内调用:
在某些时刻,运行脚本可能是在背景中,因此不可能跟用户交互 (记得 jobs, fg, bg 的情况下),此时就能够通过这种外带参数的方式来运行。 例如我们将 mypi.sh 修改成外带参数的 mypi2.sh ,读者可以这样尝试:
[student@localhost ~]$ cp ~/bin/mypi.sh ~/bin/mypi2.sh [student@localhost ~]$ vim ~/bin/mypi2.sh #!/bin/bash # Program: # User input a scale number to calculate pi number. # History: # 2015/07/16 VBird First release PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin export PATH num=${1} echo -e "This program will calculate pi value. \n" #read -p "The scale number (10~10000) ? " num echo -e "Starting calculate pi value. Be patient." time echo "scale=${num}; 4*a(1)" | bc -lq [student@localhost ~]$ chmod a+x ~/bin/mypi2.sh [student@localhost ~]$ mypi2.sh 50 This program will calculate pi value. Starting calculate pi value. Be patient. 3.14159265358979323846264338327950288419716939937508 real 0m0.001s user 0m0.000s sys 0m0.002s
读者可以发现,mypi2.sh 将 mypi.sh 内的两行输出 (说明程序功能与 read 的功能) 取消,而在不修改其他代码的情况下, 让 num=${1} 来让精确度使用第一个外带参数的方式来处理。
[root@station5-237 bin]# listcmd2.sh pwd
This shell script will list your command's full path name and permissions.
-rwxr-xr-x. 1 root root 46840 5月 12 2019 /usr/bin/pwd
getfacl: Removing leading '/' from absolute path names
# file: usr/bin/pwd
# owner: root
# group: root
user::rwx
group::r-x
other::r-x
读者可以思考 mypi.sh 这个脚本的运作,虽然指定用户应该要输入 10~10000 的数值,但是却没有在脚本中进行防呆, 因此,当用户输入 (1)非为数值的字符串及 (2)输入超过数值范围时,就可能发生程序误判的情况,如下:
[student@localhost ~]$ mypi.sh This program will calculate pi value. You should input a float number to calculate pi value. The scale number (10~10000) ? whoami Starting calculate pi value. Be patient. 0 real 0m0.001s user 0m0.001s sys 0m0.001s [student@localhost ~]$ mypi.sh This program will calculate pi value. You should input a float number to calculate pi value. The scale number (10~10000) ? <==这里直接按下 enter 就好 Starting calculate pi value. Be patient. (standard_in) 1: syntax error real 0m0.001s user 0m0.000s sys 0m0.002s
此时就会发生不可预期的错误。读者在设计程序脚本时,应该就用户可能会输入的字符或通常的运作方式进行分析, 先设计好防呆,在代码的运作上比较不容易出问题。想要达成这种防呆的机制,需要用到条件判断式的支持,一般 shell script 条件判断的语法为:
if [ 条件判断式 ]; then 当条件判断式成立时,可以进行的指令工作内容; fi <==将 if 反过来写,就成为 fi 啦!结束 if 之意!
相关条件设置的方式已经在第八堂课谈过,请自行前往参阅。若有多重条件判断,则使用下列方式:
# 一个条件判断,分成功进行与失败进行 (else) if [ 条件判断式 ]; then 当条件判断式成立时,可以进行的指令工作内容; else 当条件判断式不成立时,可以进行的指令工作内容; fi
如果考虑更复杂的情况,则可以使用这个语法:
# 多个条件判断 (if ... elif ... elif ... else) 分多种不同情况运行 if [ 条件判断式一 ]; then 当条件判断式一成立时,可以进行的指令工作内容; elif [ 条件判断式二 ]; then 当条件判断式二成立时,可以进行的指令工作内容; else 当条件判断式一与二均不成立时,可以进行的指令工作内容; fi
如果考虑两个以上的条件混合运行时,就需要使用 -a 或 -o 的协助。
# 两个条件都要成立才算成立的情况: if [ 条件判断式一 -a 条件判断二 ]; then 两个条件都成立,这时才运行 (and 的概念) fi # 两个条件中,任何一个条件成立都算 OK 的情况: if [ 条件判断式一 -o 条件判断二 ]; then 随便哪一个条件成立,都可以运行 (or 的概念) fi
以上面的语法来补足 mypi.sh 的防呆,大致防呆的思考可以是:
大致的防呆流程就像上面所叙述,接下来读者们可以使用语法来将这些流程加入 mypi.sh:
[student@localhost ~]$ vim ~/bin/mypi.sh #!/bin/bash # Program: # User input a scale number to calculate pi number. # History: # 2015/07/16 VBird First release PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin export PATH echo -e "This program will calculate pi value. \n" echo -e "You should input a float number to calculate pi value.\n" read -p "The scale number (10~10000) ? " num # 判断是否有非为数字的字符,若有,则会出现,若无则是空白 checking=$( echo ${num} | grep '[^0-9]' ) if [ "${num}" == "" -o "${checking}" != "" ]; then num=20 fi if [ "${num}" -le 10 ]; then num=10 elif [ "${num}" -ge 10000 ]; then num=10000 fi echo "Use scale number: ${num}" echo -e "Starting calculate pi value. Be patient." time echo "scale=${num}; 4*a(1)" | bc -lq
接下来请运行数次 mypi.sh ,并分别输入不同的数据 (Enter, 文本, 小于 10 的数字, 大于 10000 的数字等等), 以确认自己的处理方式应为可行。
若读者只想让 mypi.sh 的操作者体验一下 pi 的计算,因此只想给予 20, 100, 1000 三个数值, 当用户不是输入此类数值,则告知对方仅能输入这三个数值。若以 if ... then 的方式来说,需要填写的判断式稍嫌多了些。 此时可以使用 case ... esac 来做设计。
case $变量名称 in <==关键字为 case ,还有变量前有钱字号 "第一个变量内容") <==每个变量内容建议用双引号括起来,关键字则为小括号 ) 程序段 ;; <==每个类别结尾使用两个连续的分号来处理! "第二个变量内容") 程序段 ;; *) <==最后一个变量内容都会用 * 来代表所有其他值 不包含第一个变量内容与第二个变量内容的其他程序运行段 exit 1 ;; esac <==最终的 case 结尾!『反过来写』思考一下!
请使用上述的语法,搭配仅能输入 20, 100, 1000 三个数值来撰写 mypi3.sh 脚本:
[student@localhost ~]$ cp ~/bin/mypi.sh ~/bin/mypi3.sh [student@localhost ~]$ vim ~/bin/mypi3.sh #!/bin/bash # Program: # User input a scale number to calculate pi number. # History: # 2015/07/16 VBird First release PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin export PATH echo -e "This program will calculate pi value. \n" echo -e "You should input a float number to calculate pi value.\n" read -p "The scale number (20,100,1000) ? " num case ${num} in "20") echo "Your input is 20" ;; "100") echo "Your input is 100" ;; "1000") echo "Your input is 1000" ;; *) echo "You MUST input 20|100|1000" echo "I stop here" exit 0 ;; esac echo -e "Starting calculate pi value. Be patient." time echo "scale=${num}; 4*a(1)" | bc -lq [student@localhost ~]$ chmod a+x ~/bin/mypi3.sh [student@localhost ~]$ mypi3.sh This program will calculate pi value. You should input a float number to calculate pi value. The scale number (20,100,1000) ? 30 You MUST input 20|100|1000 I stop here [student@localhost ~]$ mypi3.sh This program will calculate pi value. You should input a float number to calculate pi value. The scale number (20,100,1000) ? 100 Your input is 100 Starting calculate pi value. Be patient. 3.141592653589793238462643383279502884197169399375105820974944592307\ 8164062862089986280348253421170676 real 0m0.003s user 0m0.003s sys 0m0.000s
这样就可以缩减用户输入的参数了!
事实上,一般读者只要了解基础型的正规表示法大概就已经相当足够了,不过,某些时刻为了要简化整个指令操作, 了解一下使用范围更广的延伸型正规表示法的表达式会更方便呢!举个简单的例子,一般我们要去除信息内的 (1)空白行与 (2)注解行时, 可能需要使用两次基本正规表示法,如下所示:
[student@localhost ~]$ grep -v '^$' /etc/crontab | grep -v '^#'
延伸型正规表示法,可以通过『群组』的功能,将需要截取的关键字写在一起,整个指令就会变得更清爽:
[student@localhost ~]$ egrep -v '^$|^#' /etc/crontab
grep 支持基本正规表示法,若要使用到延伸正规表示法,就得要使用 egrep 这个指令来替换才行。
熟悉了正规表示法之后,到这个延伸型的正规表示法,你应该也会想到,不就是多几个重要的特殊符号吗? 是的~所以,我们就直接来说明一下,延伸型正规表示法有哪几个特殊符号?
RE 字符 | 意义与范例 |
+ | 意义:重复『一个或一个以上』的前一个 RE 字符 范例:搜索 (god) (good) (goood)... 等等的字符串。 那个 o+ 代表『一个以上的 o 』所以,底下的运行成果会将第 1, 9, 13 行列出来。 egrep -n 'go+d' regular_express.txt |
? | 意义:『零个或一个』的前一个 RE 字符 范例:搜索 (gd) (god) 这两个字符串。 那个 o? 代表『空的或 1 个 o 』所以,上面的运行成果会将第 13, 14 行列出来。 有没有发现到,这两个案例( 'go+d' 与 'go?d' )的结果集合与 'go*d' 相同? 想想看,这是为什么喔! ^_^ egrep -n 'go?d' regular_express.txt |
| | 意义:用或( or )的方式找出数个字符串 范例:搜索 gd 或 good 这两个字符串,注意,是『或』! 所以,第 1,9,14 这三行都可以被打印出来喔!那如果还想要找出 dog 呢? egrep -n 'gd|good' regular_express.txt |
() | 意义:找出『群组』字符串 范例:搜索 (glad) 或 (good) 这两个字符串,因为 g 与 d 是重复的,所以, 我就可以将 la 与 oo 列于 ( ) 当中,并以 | 来分隔开来,就可以啦! egrep -n 'g(la|oo)d' regular_express.txt |
()+ | 意义:多个重复群组的判别 范例:将『AxyzxyzxyzxyzC』用 echo 叫出,然后再使用如下的方法搜索一下! echo 'AxyzxyzxyzxyzC' | egrep 'A(xyz)+C'上面的例子意思是说,我要找开头是 A 结尾是 C ,中间有一个以上的 "xyz" 字符串的意思~ |
以上这些就是延伸型的正规表示法的特殊字符。另外,要特别强调的是,那个 ! 在正规表示法当中并不是特殊字符, 所以,如果你想要查出来文件中含有 ! 与 > 的字行时,可以这样:
[student@localhost ~]$ grep -n '[!>]' regular_express.txt
另外,延伸正规表示法对于一般用户来说,大致上最重要的就是群组 (|) 这种用法~所以,目前只要知道 egrep 这个指令的使用时机, 以及通过 | 来分隔要同时截取的关键字即可!
作业硬盘一般操作说明:
作业当中,某些部份可能为简答题~若为简答题时,请将答案写入 /home/student/ans.txt 当中,并写好正确题号,方便老师订正答案。 请注意,文件名写错将无法上传!
请使用 root 的身份进行如下实做的任务。直接在系统上面操作,操作成功即可,上传结果的程序会主动找到你的实做结果。
作业结果传输:请以 root 的身分运行 vbird_book_check_unit 指令上传作业结果。 正常运行完毕的结果应会出现【XXXXXX_aa:bb:cc:dd:ee:ff_unitNN】字样。若需要查阅自己上传数据的时间, 请在操作系统上面使用浏览器查找: http://192.168.251.254 检查相对应的课程文件。 相关流程请参考: vbird_book_check_unit