当前位置: 首页 > news >正文

山西响应式网站建设公司局部翻新装修公司

山西响应式网站建设公司,局部翻新装修公司,聊城制作手机网站公司,十大手游代理平台排行榜shell编程 shell历史执行脚本基本语法 变量文件名代换Globbing命令代换算术代换转义字符单引号双引号Shell脚本语法 条件测试条件分支 ifthenelifelseficaseesac循环 fordodonewhiledodonebreak和continue位置参数和特殊变量输入输出 echo管道tee文件重定向函数Shell脚本调试方…   shell编程 shell历史执行脚本基本语法 变量文件名代换Globbing命令代换算术代换转义字符单引号双引号Shell脚本语法 条件测试条件分支 ifthenelifelseficaseesac循环 fordodonewhiledodonebreak和continue位置参数和特殊变量输入输出 echo管道tee文件重定向函数Shell脚本调试方法正则表达式 基本语法 字符类数量限定符位置限定符其它特殊字符Basic正则和Extended正则区别grepfindsed 常用sed命令awkC程序中使用正则习题训练   shell编程 shell历史 Shell的作用是解释执行用户的命令用户输入一条命令Shell就解释执行一条这种方式称为交互式Interactive. Shell还有一种执行命令的方式称为批处理Batch用户事先写一个Shell脚本Script其中有很多条命令让Shell一次把这些命令执行完而不必一条一条地敲命令。 Shell脚本和编程语言很相似也有变量和流程控制语句但Shell脚本是解释执行的不需要编译Shell程序从脚本中一行一行读取并执行这些命令相当于一个用户把脚本中的命令一行一行敲到Shell提示符下执行。 由于历史原因UNIX系统上有很多种Shell 1. shBourne Shell由Steve Bourne开发各种UNIX系统都配有sh。 2. cshC Shell由Bill Joy开发随BSD UNIX发布它的流程控制语句很像C语言支持很多Bourne Shell所不支持的功能作业控制命令历史命令行编辑。 3. kshKorn Shell由David Korn开发向后兼容sh的功能并且添加了csh引入的新功能是目前很多UNIX系统标准配置的Shell在这些系统上/bin/sh往往是指向/bin/ksh的符号链接。 4. tcshTENEX C Shell是csh的增强版本引入了命令补全等功能在FreeBSD、MacOS X等系统上替代了csh。 5. bashBourne Again Shell由GNU开发的Shell主要目标是与POSIX标准保持一致同时兼顾对sh的兼容bash从csh和ksh借鉴了很多功能是各种Linux发行版标准配置的Shell在Linux系统上/bin/sh往往是指向/bin/bash的符号链接。虽然如此bash和sh还是有很多不同的一方面bash扩展了一些命令和参数另一方面bash并不完全和sh兼容有些行为并不一致所以bash需要模拟sh的行为当我们通过sh这个程序名启动bash时bash可以假装自己是sh不认扩展的命令并且行为与sh保持一致。 c01cpp$ vim /etc/passwd其中最后一列显示了用户对应的shell类型root:x:0:0:root:/root:/bin/bashnobody:x:65534:65534:nobody:/nonexistent:/bin/shsyslog:x:101:103::/home/syslog:/bin/falsec01cpp:x:1000:1000:c01cpp,,,:/home/c01cpp:/bin/bashftp:x:115:125:ftp daemon,,,:/srv/ftp:/bin/false 1234567用户在命令行输入命令后一般情况下Shell会fork并exec该命令但是Shell的内建命令例外执行内建命令相当于调用Shell进程中的一个函数并不创建新的进程。以前学过的cd、alias、umask、exit等命令即是内建命令凡是用which命令查不到程序文件所在位置的命令都是内建命令内建命令没有单独的man手册要在man手册中查看内建命令应该执行 c01cpp$ man bash-builtins 1如export、shift、if、eval、[、for、while等等。内建命令虽然不创建新的进程但也会有Exit Status(退出状态返回值)通常也用0表示成功非零表示失败虽然内建命令不创建新的进程但执行结束后也会有一个状态码也可以用特殊变量$?读出。 执行脚本 编写一个简单的脚本test.sh #! /bin/sh cd .. ls 123Shell脚本中用#表示注释相当于C语言的//注释。 但如果#位于第一行开头并且是#!称为Shebang则例外它表示该脚本使用后面指定的解释器/bin/sh解释执行。 如果把这个脚本文件加上可执行权限然后执行 c01cpp$ chmod ax test.sh c01cpp$ ./test.sh 12Shell会fork一个子进程并调用exec执行./test.sh这个程序exec系统调用应该把子进程的代码段替换成./test.sh程序的代码段并从它的_start开始执行。 然而test.sh是个文本文件根本没有代码段和_start函数怎么办呢其实exec还有另外一种机制如果要执行的是一个文本文件并且第一行用Shebang指定了解释器则用解释器程序的代码段替换当前进程并且从解释器的_start开始执行而这个文本文件被当作命令行参数传给解释器。因此执行上述脚本相当于执行程序 c01cpp$ /bin/sh ./test.sh 1以这种方式执行不需要test.sh文件具有可执行权限。 如果将命令行下输入的命令用()括号括起来那么也会fork出一个子Shell执行小括号中的命令一行中可以输入由分号;隔开的多个命令比如 c01cpp$ (cd ..;ls -l) 1和上面两种方法执行Shell脚本的效果是相同的cd ..命令改变的是子Shell的PWD而不会影响到交互式Shell。然而命令 c01cpp$ cd ..;ls -l 1则有不同的效果(当前工作路径改变)cd ..命令是直接在交互式Shell下执行的改变交互式Shell的PWD然而这种方式相当于这样执行Shell脚本 c01cpp$ source ./test.sh 或者 c01cpp$ . ./test.sh 123source或者. 命令是Shell的内建命令这种方式也不会创建子Shell而是直接在交互式Shell下逐行执行脚本中的命令。 基本语法 变量 按照惯例Shell变量通常由字母加下划线开头由任意长度的字母、数字、下划线组成。 有两种类型的Shell变量 1. 环境变量 环境变量可以从父进程传给子进程因此Shell进程的环境变量可以从当前Shell进程传给fork出来的子进程。用printenv命令可以显示当前Shell进程的环境变量。 2. 本地变量 只存在于当前Shell进程用set命令可以显示当前Shell进程中定义的所有变量包括本地变量和环境变量和函数。 环境变量是任何进程都有的概念而本地变量是Shell特有的概念。在Shell中环境变量和本地变量的定义和用法相似。 在Shell中定义或赋值一个变量 c01cpp$ VARNAMEvalue 1注意等号两边都不能有空格否则会被Shell解释成命令和命令行参数。 一个变量定义后仅存在于当前Shell进程它是本地变量用export命令可以把本地变量导出为环境变量定义和导出环境变量通常可以一步完成 c01cpp$ export VARNAMEvalue 1也可以分两步完成 c01cpp$ VARNAMEvalue c01cpp$ export VARNAME 12用unset命令可以删除已定义的环境变量或本地变量。 c01cpp$ unset VARNAME 1如果一个变量叫做VARNAME用 ’ VARNAME ’ 可以表示它的值在不引起歧义的情况下也可以用VARNAME表示它的值。通过以下例子比较这两种表示法的不同 c01cpp$ SHELL c01cpp$ echo SHELL #SHELL c01cpp$ echo $SHELL #SHELL的值 123注意在定义变量时不用“’”取变量值时要用。 和C语言不同的是Shell变量不需要明确定义类型事实上Shell变量的值都是字符串比如我们定义VAR45其实VAR的值是字符串45而非整数。Shell变量不需要先定义后使用如果对一个没有定义的变量取值则值为空字符串。 文件名代换Globbing 这些用于匹配的字符称为通配符Wildcard如* ? [ ] 具体如下 * 匹配0个或多个任意字符 ? 匹配一个任意字符 [若干字符] 匹配方括号中任意一个字符的一次出现 c01cpp$ ls /dev/ttyS* c01cpp$ ls ch0?.doc c01cpp$ ls ch0[0-2].doc c01cpp$ ls ch[012] [0-9].doc 1234注意Globbing所匹配的文件名是由Shell展开的也就是说在参数还没传给程序之前已经展开了比如上述 ls ch0[012].doc 命令如果当前目录下有ch00.doc和ch02.doc则传给ls命令的参数实际上是这两个文件名而不是一个匹配字符串。 命令代换 由“”反引号括起来的也是一条命令Shell先执行该命令然后将输出结果立刻代换到当前命令行中。例如定义一个变量存放date命令的输出 c01cpp$ DATEdate c01cpp$ echo $DATE 12命令代换也可以用$()表示 c01cpp$ DATE$(date) 1算术代换 使用$(())用于算术计算(())中的Shell变量取值将转换成整数同样含义的$[ ]等价例如 c01cpp$ VAR45 c01cpp$ echo $(($VAR3)) #等价于echo $[VAR3]或 $[$VAR3] 12$(())中只能用-*/和()运算符并且只能做整数运算。 $[base#n]其中base表示进制n按照base进制解释后面再有运算数按十进制解释。 echo $[2#1011] echo $[8#1011] echo $[16#1011] 123转义字符 和C语言类似\在Shell中被用作转义字符用于去除紧跟其后的单个字符的特殊意义回车除外换句话说紧跟其后的字符取字面值。例如 c01cpp$ echo $SHELL /bin/bash c01cpp$ echo \$SHELL $SHELL c01cpp$ echo \\ \ 123456比如创建一个文件名为“$ $”的文件$间含有空格可以这样 c01cpp$ touch \$\ \$ 1还有一个字符虽然不具有特殊含义但是要用它做文件名也很麻烦就是-号。 如果要创建一个文件名以-号开头的文件这样是不正确的 c01cpp$ touch -hello touch: invalid option -- h Try touch --help for more information. 123即使加上\转义也还是报错 c01cpp$ touch \-hello touch: invalid option -- h Try touch --help for more information. 123因为各种UNIX命令都把-号开头的命令行参数当作命令的选项而不会当作文件名。 如果非要处理以-号开头的文件名可以有两种办法 c01cpp$ touch ./-hello 或者 c01cpp$ touch -- -hello 123\还有一种用法在\后敲回车表示续行Shell并不会立刻执行命令而是把光标移到下一行给出一个续行提示符等待用户继续输入最后把所有的续行接到一起当作一个命令执行。 例如 c01cpp$ ls \-l ls -l命令的输出 123单引号 和C语言同Shell脚本中的单引号和双引号一样都是字符串的界定符双引号下一节介绍而不是字符的界定符。单引号用于保持引号内所有字符的字面值即使引号内的\和回车也不例外但是字符串中不能出现单引号。如果引号没有配对就输入回车Shell会给出续行提示符要求用户把引号配上对。例如 c01cpp$ echo $SHELL $SHELL c01cpp$ echo ABC\回车DE再按一次回车结束命令 ABC\ DE 123456双引号 被双引号用括住的内容将被视为单一字串。它防止通配符扩展但允许变量扩展。 这点与单引号的处理方式不同 c01cpp$ DATE$(date) c01cpp$ echo $DATE c01cpp$ echo $DATE 123再比如 c01cpp$ VAR200 c01cpp$ echo $VAR 200 c01cpp$ echo $VAR $VAR c01cpp$ echo $VAR 200 1234567Shell脚本语法 条件测试 命令test或 [ 可以测试一个条件是否成立如果测试结果为真则该命令的Exit Status为0如果测试结果为假则命令的Exit Status为1注意与C语言的逻辑表示正好相反。 例如测试两个数的大小关系 c01cppubuntu:~$ var2 c01cppubuntu:~$ test $var -gt 1 c01cppubuntu:~$ echo $? 0 c01cppubuntu:~$ test $var -gt 3 c01cppubuntu:~$ echo $? 1 c01cppubuntu:~$ [ $var -gt 3 ] c01cppubuntu:~$ echo $? 1 c01cppubuntu:~$ 1234567891011虽然看起来很奇怪但左方括号 [ 确实是一个命令的名字传给命令的各参数之间应该用空格隔开比如 $VAR、-gt、3、] 是 [ 命令的四个参数它们之间必须用空格隔开。 命令test或 [ 的参数形式是相同的只不过test命令不需要 ] 参数。 以 [ 命令为例常见的测试命令如下表所示 [ -d DIR ] 如果DIR存在并且是一个目录则为真 [ -f FILE ] 如果FILE存在且是一个普通文件则为真 [ -z STRING ] 如果STRING的长度为零则为真 [ -n STRING ] 如果STRING的长度非零则为真 [ STRING1 STRING2 ] 如果两个字符串相同则为真 [ STRING1 ! STRING2 ] 如果字符串不相同则为真 [ ARG1 OP ARG2 ] ARG1和ARG2应该是整数或者取值为整数的变量OP是-eq等于-ne不等于-lt小于-le小于等于-gt大于-ge大于等于之中的一个。 和C语言类似测试条件之间还可以做与、或、非逻辑运算 [ ! EXPR ] EXPR可以是上表中的任意一种测试条件!表示“逻辑反(非)” [ EXPR1 -a EXPR2 ] EXPR1和EXPR2可以是上表中的任意一种测试条件-a表示“逻辑与” [ EXPR1 -o EXPR2 ] EXPR1和EXPR2可以是上表中的任意一种测试条件-o表示“逻辑或” 例如 $ VARabc $ [ -d Desktop -a $VAR abc ] $ echo $? 0 1234注意如果上例中的$VAR变量事先没有定义则被Shell展开为空字符串会造成测试条件的语法错误 展开为[ -d Desktop -a ‘abc’ ] 作为一种好的Shell编程习惯应该总是把变量取值放在双引号之中 展开为[ -d Desktop -a “” ‘abc’ ] $ unset VAR $ [ -d Desktop -a $VAR abc ] bash: [: too many arguments $ [ -d Desktop -a $VAR abc ] $ echo $? 1 123456条件分支 if/then/elif/else/fi 和C语言类似在Shell中用if、then、elif、else、fi这几条命令实现分支控制。这种流程控制语句本质上也是由若干条Shell命令组成的例如先前讲过的 if [ -f ~/.bashrc ]; then. ~/.bashrc fi 123其实是三条命令 if [ -f ∼/.bashrc ]是第一条 then . ∼/.bashrc是第二条 fi是第三条。 如果两条命令写在同一行则需要用;号隔开一行只写一条命令就不需要写;号了 另外then后面有换行但这条命令没写完Shell会自动续行把下一行接在then后面当作一条命令处理。 和[命令一样要注意命令和各参数之间必须用空格隔开。if命令的参数组成一条子命令如果该子命令的Exit Status为0表示真则执行then后面的子命令如果Exit Status非0表示假则执行elif、else或者fi后面的子命令。 if后面的子命令通常是测试命令但也可以是其它命令。 Shell脚本没有{}括号所以用fi表示if语句块的结束。见下例 #! /bin/shif [ -f /bin/bash ] then echo /bin/bash is a file else echo /bin/bash is NOT a file fi if :; then echo always true; fi 123456789“:”是一个特殊的命令称为空命令该命令不做任何事但Exit Status总是真。 此外也可以执行/bin/true或/bin/false得到真或假的Exit Status。 再看一个例子 #! /bin/shecho Is it morning? Please answer yes or no. read YES_OR_NO if [ $YES_OR_NO yes ]; thenecho Good morning! elif [ $YES_OR_NO no ]; thenecho Good afternoon! elseecho Sorry, $YES_OR_NO not recognized. Enter yes or no.exit 1 fi exit 0 12345678910111213上例中的read命令的作用是等待用户输入一行字符串将该字符串存到一个Shell变量中。 此外Shell还提供了和||语法和C语言类似具有Short-circuit短路原则特性很多Shell脚本喜欢写成这样 test $(whoami) ! root (echo you are using a non-privileged account; exit 1) 1相当于“if…then…”而||相当于“if not…then…”。 和||用于连接两个命令而上面讲的-a和-o仅用于在测试表达式中连接两个测试条件要注意它们的区别例如 test $VAR -gt 1 -a $VAR -lt 3 1和以下写法是等价的 test $VAR -gt 1 test $VAR -lt 3 1case/esac case命令可类比C语言的switch/case语句esac表示case语句块的结束。 C语言的case只能匹配整型或字符型常量表达式而Shell脚本的case可以匹配字符串和Wildcard每个匹配分支可以有若干条命令末尾必须以;;结束执行时找到第一个匹配的分支并执行相应的命令然后直接跳到esac之后不需要像C语言一样用break跳出。 #! /bin/shecho Is it morning? Please answer yes or no. read YES_OR_NO case $YES_OR_NO in yes|y|Yes|YES)echo Good Morning!;; [nN]*)echo Good Afternoon!;; *)echo Sorry, $YES_OR_NO not recognized. Enter yes or no.exit 1;; esac exit 0 1234567891011121314使用case语句的例子可以在系统服务的脚本目录/etc/init.d中找到。这个目录下的脚本大多具有这种形式以/etc/init.d/nfs-kernel-server为例 case $1 instart)...;;stop)...;;reload | force-reload)...;;restart)...*)log_success_msgUsage: nfs-kernel-server {start|stop|status|reload|force-reload|restart}exit 1;; esac 1234567891011121314151617启动nfs-kernel-server服务的命令是 $ sudo /etc/init.d/nfs-kernel-server start 1$1是一个特殊变量在执行脚本时自动取值为第一个命令行参数也就是start所以进入start)分支执行相关的命令。同理命令行参数指定为stop、reload或restart可以进入其它分支执行停止服务、重新加载配置文件或重新启动服务的相关命令。 循环 for/do/done Shell脚本的for循环结构和C语言很不一样它类似于某些编程语言的foreach循环(迭代器)。例如 #! /bin/shfor FRUIT in apple banana pear; doecho I like $FRUIT done 12345FRUIT是一个循环变量第一次循环$FRUIT的取值是apple第二次取值是banana第三次取值是pear。 再比如要将当前目录下的chap0、chap1、chap2等文件名改为chap0~、chap1~、chap2~等按惯例末尾有~字符的文件名表示临时文件这个命令可以这样写 $ for FILENAME in chap?; do mv $FILENAME $FILENAME~; done 1也可以这样写 $ for FILENAME in ls chap?; do mv $FILENAME $FILENAME~; done 1while/do/done while的用法和C语言类似。比如一个验证密码的脚本 #! /bin/shecho Enter password: read TRY while [ $TRY ! secret ]; doecho Sorry, try againread TRY done 12345678下面的例子通过算术运算控制循环的次数 #! /bin/shCOUNTER1 while [ $COUNTER -lt 10 ]; doecho Here we go againCOUNTER$(($COUNTER1)) done 1234567另Shell还有until循环类似C语言的do…while。 break和continue break n 可以指定跳出几层循环 continue跳过本次循环但不会跳出循环continue n 可以指定跳过几层循环。 即break跳出continue跳过。 练习将上面验证密码的程序修改一下如果用户输错五次密码就报错退出。 #! /bin/shecho Enter password: COUNTER0 read TRY while [ $TRY ! secret ]; doCOUNTER$(($COUNTER1))if [ $COUNTER -eq 5 ]then echo Sorry, permission deniedbreakelseecho Sorry, try againread TRYfi done echo identity varified123456789101112131415161718位置参数和特殊变量 有很多特殊变量是被Shell自动赋值的我们已经遇到了$?和$1。其他常用的位置参数和特殊变量在这里总结一下 $0 相当于C语言main函数的argv[0] $1、$2… 这些称为位置参数Positional Parameter相当于C语言main函数的argv[1]、argv[2]… $# 相当于C语言main函数的argc - 1注意这里的#后面不表示注释 $ 表示参数列表”$1” “$2” …例如可以用在for循环中的in后面。 $* 表示参数列表”$1” “$2” …同上 $? 上一条命令的Exit Status $$ 当前进程号 位置参数可以用shift命令左移。 比如shift 3表示原来的$4现在变成$1原来的$5现在变成$2等等原来的$1、$2、$3丢弃$0不移动。 不带参数的shift命令相当于shift 1。 例如 #! /bin/shecho The program $0 is now running echo The first parameter is $1 echo The second parameter is $2 echo The parameter list is $ shift echo The first parameter is $1 echo The second parameter is $2 echo The parameter list is $ 12345678910$ ./shift.sh 1 2 3 4 5 The program ./shift.sh is now running The first parameter is 1 The second parameter is 2 The parameter list is 1 2 3 4 5 The first parameter is 2 The second parameter is 3 The parameter list is 2 3 4 5 12345678输入输出 echo 显示文本行或变量或者把字符串输入到文件。 echo [option] string -e 解析转义字符 -n 不回车换行。默认情况echo回显的内容后面跟一个回车换行。 echo hello\n\n echo -e hello\n\n echo hello echo -n hello 1234管道 可以通过 | 把一个命令的输出传递给另一个命令做输入。 cat myfile | more ls -l | grep myfile df -k | awk {print $1} | grep -v 文件系统 123df -k 查看磁盘空间找到第一列去除“文件系统”并输出 tee tee命令把结果输出到标准输出另一个副本输出到相应文件。 df -k | awk {print $1} | grep -v 文件系统 | tee a.txt 1tee -a a.txt表示追加操作。 df -k | awk {print $1} | grep -v 文件系统 | tee -a a.txt 1文件重定向 cmd file 把标准输出重定向到新文件中 cmd file 追加 cmd file 21 标准出错也重定向到1所指向的file里 表示等同于的意思 cmd file 21 cmd file1 file2 输入输出都定向到文件里file1输入输出到file2 cmd fd 把文件描述符fd作为标准输入 cmd fd 把文件描述符fd作为标准输出 cmd - 关闭标准输入 函数 和C语言类似Shell中也有函数的概念但是函数定义中没有返回值也没有参数列表。 例如 #! /bin/shfoo(){ echo Function foo is called;} echo -start- foo echo -end- 123456注意函数体的左花括号 { 和后面的命令之间必须有空格或换行 如果将最后一条命令和右花括号 } 写在同一行命令末尾必须有分号;。 但不建议将函数定义写至一行上不利于脚本阅读。 在定义foo()函数时并不执行函数体中的命令就像定义变量一样只是给foo这个名一个定义到后面调用foo函数的时候注意Shell中的函数调用不写括号才执行函数体中的命令。 Shell脚本中的函数必须先定义后调用一般把函数定义语句写在脚本的前面把函数调用和其它命令写在脚本的最后类似C语言中的main函数这才是整个脚本实际开始执行命令的地方。 Shell函数没有参数列表并不表示不能传参数事实上函数就像是迷你脚本调用函数时可以传任意个参数。 在函数内同样是用$0、$1、$2等变量来提取参数函数中的位置参数相当于函数的局部变量改变这些变量并不会影响函数外面的$0、$1、$2等变量。 函数中可以用return命令返回如果return后面跟一个数字则表示函数的Exit Status。 下面这个脚本可以一次创建多个目录各目录名通过命令行参数传入脚本逐个测试各目录是否存在如果目录不存在首先打印信息然后试着创建该目录。 #! /bin/shis_directory() {DIR_NAME$1if [ ! -d $DIR_NAME ]; thenreturn 1elsereturn 0fi } for DIR in $; doif is_directory $DIRthen :elseecho $DIR doesnt exist. Creating it now...mkdir $DIR /dev/null 21 #标准出错也重定向到空设备文件里#1 表示stdout标准输出系统默认值是1所以”/dev/null”等同于 “1/dev/null”。因此/dev/null 21也可以写成“1 /dev/null 2 1”if [ $? -ne 0 ]; thenecho Cannot create directory $DIRexit 1fifi done 123456789101112131415161718192021222324注意is_directory()返回0表示真返回1表示假。 command file 2file 与command file 21 它们 有什么不同的地方吗 首先command file 2file 的意思是将命令所产生的标准输出信息,和错误的输出信息送到file 中.command file 2file 这样的写法,stdout和stderr都直接送到file中, file会被打开两次,这样stdout和stderr会互相覆盖,这样写相当使用了fd1和fd2两个同时去抢占file 的管道。 而command file 21 这条命令就将stdout直接送向file, stderr 继承了FD1管道后,再被送往file,此时,file 只被打开了一次,也只使用了一个管道FD1,它包括了stdout和stderr的内容。 从IO效率上,前一条命令的效率要比后面一条的命令效率要低,所以在编写shell脚本的时候,较多的时候我们会command file 21 这样的写法。 Shell脚本调试方法 Shell提供了一些用于调试脚本的选项如 -n 读一遍脚本中的命令但不执行用于检查脚本中的语法错误。 -v 一边执行脚本一边将执行过的脚本命令打印到标准错误输出。 -x 提供跟踪执行信息将执行的每一条命令和结果依次打印出来。 这些选项有三种常见的使用方法 1.在命令行提供参数。如 $ sh -x ./script.sh 12.在脚本开头提供参数。如 #! /bin/sh -x 13.在脚本中用set命令启用或禁用参数。如 #! /bin/shif [ -z $1 ]; thenset -xecho ERROR: Insufficient Args.exit 1set x fi 12345678set -x和set x分别表示启用和禁用-x参数这样可以只对脚本中的某一段进行跟踪调试。 正则表达式 以前我们用grep在一个文件中找出包含某些字符串的行比如在头文件中找出一个宏定义。 其实grep还可以找出符合某个模式Pattern的一类字符串。例如找出所有符合xxxxxxxxx.xxx模式的字符串也就是email地址要求x字符可以是字母、数字、下划线、小数点或减号email地址的每一部分可以有一个或多个x字符例如abc.def.com、1_2987-6.54当然符合这个模式的不全是合法的email地址但至少可以做一次初步筛选筛掉a.b、cd等肯定不是email地址的字符串。 再比如找出所有符合yyy.yyy.yyy.yyy模式的字符串也就是IP地址要求y是0-9的数字IP地址的每一部分可以有1-3个y字符。 如果要用grep查找一个模式如何表示这个模式这一类字符串而不是一个特定的字符串呢从这两个简单的例子可以看出要表示一个模式至少应该包含以下信息 字符类Character Class如上例的x和y它们在模式中表示一个字符但是取值范围是一类字符中的任意一个。 数量限定符Quantifier 邮件地址的每一部分可以有一个或多个x字符IP地址的每一部分可以有1-3个y字符。 各种字符类以及普通字符之间的位置关系例如邮件地址分三部分用普通字符和.隔开IP地址分四部分用.隔开每一部分都可以用字符类和数量限定符描述。 为了表示位置关系还有位置限定符Anchor的概念将在下面介绍。 规定一些特殊语法表示字符类、数量限定符和位置关系然后用这些特殊语法和普通字符一起表示一个模式这就是正则表达式Regular Expression。 例如 email地址的正则表达式可以写成[a-zA-Z0-9.-][a-zA-Z0-9.-].[a-zA-Z0-9_.-] IP地址的正则表达式可以写成[0-9]{1,3}.[0-9]{1,3}.[0-9]{1,3}.[0-9]{1,3}。 下一节介绍正则表达式的语法我们先看看正则表达式在grep中怎么用。例如有这样一个文本文件testfile 192.168.1.1 1234.234.04.5678 123.4234.045.678 abcde $ egrep [0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3} testfile 192.168.1.1 1234.234.04.5678 1234567egrep相当于grep -E表示采用Extended正则表达式语法。grep的正则表达式有Basic和Extended两种规范它们之间的区别下一节再解释。 另外还有fgrep命令相当于grep -F表示只搜索固定字符串而不搜索正则表达式模式不会按正则表达式的语法解释后面的参数。 注意正则表达式参数用单引号括起来了因为正则表达式中用到的很多特殊字符在Shell中也有特殊含义例如只有用单引号括起来才能保证这些字符原封不动地传给grep命令而不会被Shell解释掉。 192.168.1.1符合上述模式由三个.隔开的四段组成每段都是1到3个数字所以这一行被找出来了可为什么1234.234.04.5678也被找出来了呢因为grep找的是包含某一模式的行这一行包含一个符合模式的字符串234.234.04.567。相反123.4234.045.678这一行不包含符合模式的字符串所以不会被找出来。 grep是一种查找过滤工具正则表达式在grep中用来查找符合模式的字符串。其实正则表达式还有一个重要的应用是验证用户输入是否合法 例如用户通过网页表单提交自己的email地址就需要用程序验证一下是不是合法的email地址这个工作可以在网页的Javascript中做也可以在网站后台的程序中做例如PHP、Perl、Python、Ruby、Java或C所有这些语言都支持正则表达式可以说目前不支持正则表达式的编程语言实在很少见。 除了编程语言之外很多UNIX命令和工具也都支持正则表达式例如grep、vi、sed、awk、emacs等等。“正则表达式”就像“变量”一样它是一个广泛的概念而不是某一种工具或编程语言的特性。 基本语法 我们知道C的变量和Shell脚本变量的定义和使用方法很不相同表达能力也不相同C的变量有各种类型而Shell脚本变量都是字符串。同样道理各种工具和编程语言所使用的正则表达式规范的语法并不相同表达能力也各不相同有的正则表达式规范引入很多扩展能表达更复杂的模式但各种正则表达式规范的基本概念都是相通的。 本节介绍egrep(1)所使用的正则表达式它大致上符合POSIX正则表达式规范详见regex(7)看这个man page对你的英文绝对是很好的锻炼。希望读者仿照上一节的例子一边学习语法一边用egrep命令做实验。 字符类 数量限定符 再次注意grep找的是包含某一模式的行而不是完全匹配某一模式的行。 例如有如下文本 aaabc aad efg 123查找a*这个模式的结果。会发现三行都被找了出来。 $ egrep a* testfile aaabc aad efg 1234a匹配0个或多个a而第三行包含0个a所以也包含了这一模式。单独用a这样的正则表达式做查找没什么意义一般是把a*作为正则表达式的一部分来用。 位置限定符 位置限定符可以帮助grep更准确地查找。 例如上一节我们用[0-9]{1,3}.[0-9]{1,3}.[0-9]{1,3}.[0-9]{1,3}查找IP地址找到这两行 192.168.1.1 1234.234.04.5678 12如果用^[0-9]{1,3}.[0-9]{1,3}.[0-9]{1,3}.[0-9]{1,3}$查找就可以把1234.234.04.5678这一行过滤掉了。 其它特殊字符 Basic正则和Extended正则区别 以上介绍的是grep正则表达式的Extended规范Basic规范也有这些语法只是字符?{}|()应解释为普通字符要表示上述特殊含义则需要加\转义。如果用grep而不是egrep并且不加-E参数则应该遵照Basic规范来写正则表达式。 grep 1.作用 Linux系统中grep命令是一种强大的文本搜索工具它能使用正则表达式搜索文本并把匹 配的行打印出来。grep全称是Global Regular Expression Print表示全局正则表达式版本它的使用权限是所有用户。 grep家族包括grep、egrep和fgrep。egrep和fgrep的命令只跟grep有很小不同。egrep是grep的扩展支持更多的re元字符 fgrep就是fixed grep或fast grep它们把所有的字母都看作单词也就是说正则表达式中的元字符表示回其自身的字面意义不再特殊。 linux使用GNU版本的grep。它功能更强可以通过-G、-E、-F命令行选项来使用egrep和fgrep的功能。 2. 格式及主要参数 grep [options] 主要参数 grep –help可查看 -c只输出匹配行的计数。 -i不区分大小写。 -h查询多文件时不显示文件名。 -l查询多文件时只输出包含匹配字符的文件名。 -n显示匹配行及 行号。 -s不显示不存在或无匹配文本的错误信息。 -v显示不包含匹配文本的所有行。 –colorauto 可以将找到的关键词部分加上颜色的显示。 pattern正则表达式主要参数: \ 忽略正则表达式中特殊字符的原有含义。 ^匹配正则表达式的开始行。 $: 匹配正则表达式的结束行。 \从匹配正则表达 式的行开始。 到匹配正则表达式的行结束。 [ ]单个字符如[A]即A符合要求 。 [ - ]范围如[A-Z]即A、B、C一直到Z都符合要求 。 .所有的单个字符。 *所有字符长度可以为0。 3.grep命令使用简单实例 显示所有以d开头的文件中包含 test的行 c01cpp$ grep ‘test’ d* 1显示在aabbcc文件中匹配test的行。 c01cpp $ grep ‘test’ aa bb cc 1显示所有包含每个字符串至少有5个连续小写字符的字符串的行。 c01cpp $ grep ‘[a-z]\{5\}’ aa 1如果west被匹配则es就被存储到内存中并标记为1然后搜索任意个字符(.*)这些字符后面紧跟着 另外一个es(\1)找到就显示该行。如果用egrep或grep -E就不用”\”号进行转义直接写成w(es)t.*\1就可以了。 c01cpp $ grep ‘w\(es\)t.*\1′ aa 14.grep命令使用复杂实例 明确要求搜索子目录 grep -r 1或忽略子目录 grep -d skip 1如果有很多输出时可以通过管道将其转到’less’上阅读 c01cpp$ grep magic /usr/src/Linux/Documentation/* | less 1有一点要注意您必需提供一个文件过滤方式(搜索全部文件的话用 *)。如果您忘了grep会一直等着直到该程序被中断。如果您遇到了这样的情况按 然后再试。 下面还有一些有意思的命令行参数 grep -i pattern files 不区分大小写地搜索。默认情况区分大小写 grep -l pattern files 只列出匹配的文件名 grep -L pattern files 列出不匹配的文件名 grep -w pattern files 只匹配整个单词而不是字符串的一部分(如匹配’magic’而不是’magical’) grep -C number pattern files 匹配的上下文分别显示[number]行 grep pattern1 | pattern2 files 显示匹配 pattern1 或 pattern2 的行 例如grep “abc|xyz” testfile 表示过滤包含abc或xyz的行 grep pattern1 files | grep pattern2 显示既匹配 pattern1 又匹配 pattern2 的行。 grep -n pattern files 即可显示行号信息 grep -c pattern files 即可查找总行数 还有些用于搜索的特殊符号\ 和 \ 分别标注单词的开始与结尾。 例如 grep man * 会匹配 ‘Batman’、’manic’、’man’等 grep ‘\man’ * 匹配’manic’和’man’但不是’Batman’ grep ‘\man\’ 只匹配’man’而不是’Batman’或’manic’等其他的字符串。 ‘^’ 指匹配的字符串在行首 ‘$’ 指匹配的字符串在行 尾 find 由于find具有强大的功能所以它的选项也很多其中大部分选项都值得我们花时间来了解一下。 即使系统中含有网络文件系统( NFS)find命令在该文件系统中同样有效只要你具有相应的权限。 在运行一个非常消耗资源的find命令时很多人都倾向于把它放在后台执行因为遍历一个大的文件系统可能会花费很长的时间(这里是指30G字节以上的文件系统)。 一、 find 命令格式 1、 find命令的一般形式为 find pathname -options [-print -exec -ok …] 2、 find命令的参数 pathname: find命令所查找的目录路径。例如用.来表示当前目录用/来表示系统根目录递归查找。 -print find命令将匹配的文件输出到标准输出。 -exec find命令对匹配的文件执行该参数所给出的shell命令。相应命令的形式为’command’ {} \;注意{}内部无空格和\之间含有一个空格分隔符。 -ok 和-exec的作用相同只不过以一种更为安全的模式来执行该参数所给出的shell命令在执行每一个命令之前都会给出提示让用户来确定是否执行。 3、 find命令选项 -name 按照文件名查找文件。 -perm 按照文件权限来查找文件。 -prune 使用这一选项可以使find命令不在当前指定的目录中查找如果同时使用-depth选项那么-prune将被find命令忽略。 -user 按照文件属主来查找文件。 -group 按照文件所属的组来查找文件。 -mtime -n n 按照文件的更改时间来查找文件-n表示文件更改时间距现在n天以内n表示文件更改时间距现在n天以前。find命令还有-atime和-ctime 选项但它们都和-m time选项。 -nogroup 查找无有效所属组的文件即该文件所属的组在/etc/groups中不存在。 -nouser 查找无有效属主的文件即该文件的属主在/etc/passwd中不存在。 -newer file1 ! file2 查找更改时间比文件file1新但比文件file2旧的文件。 -type 查找某一类型的文件诸如 b - 块设备文件。 d - 目录。 c - 字符设备文件。 p - 管道文件。 l - 符号链接文件。 f - 普通文件。 -size n[c] 查找文件长度为n块的文件带有c时表示文件长度以字节计。 -depth 在查找文件时首先查找当前目录中的文件然后再在其子目录中查找。 -fstype 查找位于某一类型文件系统中的文件这些文件系统类型通常可以在配置文件/etc/fstab中找到该配置文件中包含了本系统中有关文件系统的信息。 -mount 在查找文件时不跨越文件系统mount点。 -follow 如果find命令遇到符号链接文件就跟踪至链接所指向的文件。 另外,下面三个的区别: -amin n 查找系统中最后N分钟访问的文件 -atime n 查找系统中最后n*24小时访问的文件 -cmin n 查找系统中最后N分钟被改变文件状态的文件 -ctime n 查找系统中最后n*24小时被改变文件状态的文件 -mmin n 查找系统中最后N分钟被改变文件数据的文件 -mtime n 查找系统中最后n*24小时被改变文件数据的文件 4、 使用exec或ok来执行shell命令 使用find时只要把想要的操作写在一个文件里就可以用exec来配合find查找。 在有些操作系统中只允许-exec选项执行诸如ls或ls -l这样的命令。大多数用户使用这一选项是为了查找旧文件并删除它们。 建议在真正执行rm命令删除文件之前最好先用ls命令看一下确认它们是所要删除的文件。 exec选项后面跟随着所要执行的命令或脚本然后是一对{}一个空格和一个\最后是一个分号。 为了使用exec选项必须要同时使用print选项。如果验证一下find命令会发现该命令只输出从当前路径起的相对路径及文件名。 例如为了用ls -l命令列出所匹配到的文件可以把ls -l命令放在find命令的-exec选项中 # find . -type f -exec ls -l {} \; 1上面的例子中find命令匹配到了当前目录下的所有普通文件并在-exec选项中使用ls -l命令将它们列出。 在/logs目录中查找更改时间在5日以前的文件并删除它们 $ find logs -type f -mtime 5 -exec rm {} \; 1记住在shell中用任何方式删除文件之前应当先查看相应的文件一定要小心 当使用诸如mv或rm命令时可以使用-exec选项的安全模式。它将在对每个匹配到的文件进行操作之前提示你。 在下面的例子中 find命令在当前目录中查找所有文件名以.LOG结尾、更改时间在5日以上的文件并删除它们只不过在删除之前先给出提示。 $ find . -name *.conf -mtime 5 -ok rm {} \;rm ... ./conf/httpd.conf ? n 12按y键删除文件按n键不删除。 任何形式的命令都可以在-exec选项中使用。 在下面的例子中我们使用grep命令。find命令首先匹配所有文件名为“ passwd*”的文件例如passwd、passwd.old、passwd.bak然后执行grep命令看看在这些文件中是否存在一个c01cpp用户。 # find /etc -name passwd* -exec grep c01cpp {} \; c01cpp:x:1000:1000::/home/c01cpp:/bin/bash 12二、 find命令的例子 1、 查找当前用户主目录下的所有文件 下面两种方法都可以使用 $ find $HOME -print $ find ~ -print 122、 让当前目录中文件属主具有读、写权限并且文件所属组的用户和其他用户具有读权限的文件 $ find . -type f -perm 644 -exec ls -l {} \; 13、 为了查找系统中所有文件长度为0的普通文件并列出它们的完整路径 $ find / -type f -size 0 -exec ls -l {} \; 14、 查找/var/logs目录中更改时间在7日以前的普通文件并在删除之前询问它们 $ find /var/logs -type f -mtime 7 -ok rm {} \; 15、 为了查找系统中所有属于root组的文件 $find . -group root -exec ls -l {} \; 16、 find命令将删除当目录中访问时间在7日以来、含有数字后缀的admin.log文件。 该命令只检查三位数字所以相应文件的后缀不要超过999。先建几个admin.log*的文件 才能使用下面这个命令 $ find . -name admin.log[0-9][0-9][0-9] -atime -7 -ok rm {} \; 17、 为了查找当前文件系统中的所有目录并排序 $ find . -type d | sort 1三、 xargs xargs - build and execute command lines from standard input 在使用find命令的-exec选项处理匹配到的文件时 find命令将所有匹配到的文件一起传递给exec执行。 但有些系统对能够传递给exec的命令长度有限制这样在find命令运行几分钟之后就会出现 溢出错误。错误信息通常是“参数列太长”或“参数列溢出”。 这就是xargs命令的用处所在特别是与find命令一起使用。 find命令把匹配到的文件传递给xargs命令而xargs命令每次只获取一部分文件而不是全部不像-exec选项那样。这样它可以先处理最先获取的一部分文件然后是下一批并如此继续下去。 在有些系统中使用-exec选项会为处理每一个匹配到的文件而发起一个相应的进程并非将匹配到的文件全部作为参数一次执行这样在有些情况下就会出现进程过多系统性能下降的问题因而效率不高 而使用xargs命令则只有一个进程。另外在使用xargs命令时究竟是一次获取所有的参数还是分批取得参数以及每一次获取参数的数目都会根据该命令的选项及系统内核中相应的可调参数来确定。 来看看xargs命令是如何同find命令一起使用的并给出一些例子。 下面的例子查找系统中的每一个普通文件然后使用xargs命令来测试它们分别属于哪类文件 #find . -type f -print | xargs file 1在当前目录下查找所有用户具有读、写和执行权限的文件并收回相应的写权限 # ls -l # find . -perm -7 -print | xargs chmod o-w # ls -l 123用grep命令在所有的普通文件中搜索hello这个词 # find . -type f -print | xargs grep hello 1用grep命令在当前目录下的所有普通文件中搜索hello这个词 # find . -name \* -type f -print | xargs grep hello 1注意在上面的例子中 \用来取消find命令中的*在shell中的特殊含义。 find命令配合使用exec和xargs可以使用户对所匹配到的文件执行几乎所有的命令。 四、 find 命令的参数 下面是find一些常用参数的例子有用到的时候查查就行了也可以用man。 1、 使用name选项 文件名选项是find命令最常用的选项要么单独使用该选项要么和其他选项一起使用。 可以使用某种文件名模式来匹配文件记住要用引号将文件名模式引起来。 不管当前路径是什么如果想要在自己的根目录HOME中查找文件名符合∗.txt的文件使用‘~’作为 ‘pathname’ 的参数波浪号代表了你的HOME目录。 $ find ~ -name *.txt -print 1想要在当前目录及子目录中查找所有的‘ *.txt’文件可以用 $ find . -name *.txt -print 1想要的当前目录及子目录中查找文件名以一个大写字母开头的文件可以用 $ find . -name [A-Z]* -print 1想要在/etc目录中查找文件名以host开头的文件可以用 $ find /etc -name host* -print 1想要查找$HOME目录中的文件可以用 $ find ~ -name * -print 或find . –print 1要想让系统高负荷运行就从根目录开始查找所有的文件 $ find / -name * -print 1如果想在当前目录查找文件名以两个小写字母开头跟着是两个数字最后是.txt的文件下面的命令就能够返回例如名为ax37.txt的文件 $find . -name [a-z][a-z][0-9][0-9].txt -print 12、 用perm选项 按照文件权限模式用-perm选项,按文件权限模式来查找文件的话。最好使用八进制的权限表示法。 如在当前目录下查找文件权限位为755的文件即文件属主可以读、写、执行其他用户可以读、执行的文件可以用 $ find . -perm 755 -print 1还有一种表达方法在八进制数字前面要加一个横杠-表示都匹配如-007就相当于777-006相当于666 # ls -l # find . -perm 006 # find . -perm -006 123 -perm mode:文件许可正好符合mode -perm mode:文件许可部分符合mode -perm -mode: 文件许可完全符合mode 3、 忽略某个目录 如果在查找文件时希望忽略某个目录因为你知道那个目录中没有你所要查找的文件那么可以使用-prune选项来指出需要忽略的目录。在使用-prune选项时要当心因为如果你同时使用了-depth选项那么-prune选项就会被find命令忽略。 如果希望在/apps目录下查找文件但不希望在/apps/bin目录下查找可以用 $ find /apps -path /apps/bin -prune -o -print 14、 使用find查找文件的时候怎么避开某个文件目录 比如要在/home/c01cpp目录下查找不在dir1子目录之内的所有文件 find /home/c01cpp -path /home/c01cpp/dir1 -prune -o -print 1避开多个文件夹 find /home \( -path /home/c01cpp/f1 -o -path /home/c01cpp/f2 \) -prune -o -print 1注意(前的\注意(后的空格。 5、 使用user和nouser选项 按文件属主查找文件如在$HOME目录中查找文件属主为c01cpp的文件可以用 $ find ~ -user c01cpp -print 1在/etc目录下查找文件属主为uucp的文件 $ find /etc -user uucp -print 1为了查找属主帐户已经被删除的文件可以使用-nouser选项。这样就能够找到那些属主在/etc/passwd文件中没有有效帐户的文件。在使用-nouser选项时不必给出用户名find命令能够为你完成相应的工作。 例如希望在/home目录下查找所有的这类文件可以用 $ find /home -nouser -print 16、 使用group和nogroup选项 就像user和nouser选项一样针对文件所属于的用户组 find命令也具有同样的选项为了在/apps目录下查找属于c01cpp用户组的文件可以用 $ find /apps -group c01cpp -print 1要查找没有有效所属用户组的所有文件可以使用nogroup选项。下面的find命令从文件系统的根目录处查找这样的文件 $ find / -nogroup -print 17、 按照更改时间或访问时间等查找文件 如果希望按照更改时间来查找文件可以使用mtime,atime或ctime选项。如果系统突然没有可用空间了很有可能某一个文件的长度在此期间增长迅速这时就可以用mtime选项来查找这样的文件。 用减号-来限定更改时间在距今n日以内的文件而用加号来限定更改时间在距今n日以前的文件。 希望在系统根目录下查找更改时间在5日以内的文件可以用 $ find / -mtime -5 -print 1为了在/var/adm目录下查找更改时间在3日以前的文件可以用 $ find /var/adm -mtime 3 -print 18、 查找比某个文件新或旧的文件 如果希望查找更改时间比某个文件新但比另一个文件旧的所有文件可以使用-newer选项。它的一般形式为 newest_file_name ! oldest_file_name 1其中是逻辑非符号。 9、 使用type选项 在/etc目录下查找所有的目录可以用 $ find /etc -type d -print 1在当前目录下查找除目录以外的所有类型的文件可以用 $ find . ! -type d -print 1在/etc目录下查找所有的符号链接文件可以用 $ find /etc -type l -print 110、 使用size选项 可以按照文件长度来查找文件这里所指的文件长度既可以用块block来计量也可以用字节来计量。以字节计量文件长度的表达形式为N c以块计量文件长度只用数字表示即可。 在按照文件长度查找文件时一般使用这种以字节表示的文件长度在查看文件系统的大小因为这时使用块来计量更容易转换。 在当前目录下查找文件长度大于1 M字节的文件 $ find . -size 1000000c -print 1在/home/apache目录下查找文件长度恰好为100字节的文件 $ find /home/apache -size 100c -print 1在当前目录下查找长度超过10块的文件一块等于512字节 $ find . -size 10 -print 111、 使用depth选项 在使用find命令时可能希望先匹配所有的文件再在子目录中查找。使用depth选项就可以使find命令这样做。这样做的一个原因就是当在使用find命令向磁带上备份文件系统时希望首先备份所有的文件其次再备份子目录中的文件。 在下面的例子中 find命令从文件系统的根目录开始查找一个名为CON.FILE的文件。 它将首先匹配所有的文件然后再进入子目录中查找。 $ find / -name CON.FILE -depth -print 112、 使用mount选项 在当前的文件系统中查找文件不进入其他文件系统可以使用find命令的mount选项。 从当前目录开始查找位于本文件系统中文件名以XC结尾的文件 $ find . -name *.XC -mount -print 1练习请找出你10天内所访问或修改过的.c和.cpp文件。 sed sed意为流编辑器Stream Editor在Shell脚本和Makefile中作为过滤器使用非常普遍也就是把前一个程序的输出引入sed的输入经过一系列编辑命令转换为另一种格式输出。sed和vi都源于早期UNIX的ed工具所以很多sed命令和vi的末行命令是相同的。 sed命令行的基本格式为 sed option ‘script’ file1 file2 … sed option -f scriptfile file1 file2 … 选项含义 –version 显示sed版本。 –help 显示帮助文档。 -n,–quiet,–silent 静默输出默认情况下sed程序在所有的脚本指令执行完毕后将自动打印模式空间中的内容这些选项可以屏蔽自动打印。 -e script 允许多个脚本指令被执行。 -f script-file, –filescript-file 从文件中读取脚本指令对编写自动脚本程序来说很棒 -i,–in-place 直接修改源文件经过脚本指令处理后的内容将被输出至源文件源文件被修改慎用 -l N, –line-lengthN 该选项指定l指令可以输出的行长度l指令用于输出非打印字符。 –posix 禁用GNU sed扩展功能。 -r, –regexp-extended 在脚本指令中使用扩展正则表达式 -s, –separate 默认情况下sed将把命令行指定的多个文件名作为一个长的连续的输入流。而GNU sed则允许把他们当作单独的文件这样如正则表达式则不进行跨文件匹配。 -u, –unbuffered 最低限度的缓存输入与输出。 以上仅是sed程序本身的选项功能说明至于具体的脚本指令即对文件内容做的操作后面我们会详细描述这里就简单介绍几个脚本指令操作作为sed程序的例子。 a, append 追加 i, insert 插入 d, delete 删除 s, substitution 替换 如 $ sed 2a c01cpp ./testfile #在输出testfile内容的第二行后添加c01cpp。 1$ sed 2,5d testfile 1sed处理的文件既可以由标准输入重定向得到也可以当命令行参数传入命令行参数可以一次传入多个文件sed会依次处理。 sed的编辑命令可以直接当命令行参数传入也可以写成一个脚本文件然后用-f参数指定编辑命令的格式为 /pattern/action 其中pattern是正则表达式action是编辑操作。sed程序一行一行读出待处理文件如果某一行与pattern匹配则执行相应的action如果一条命令没有pattern而只有action这个action将作用于待处理文件的每一行。 常用sed命令 /pattern/p 打印匹配pattern的行 /pattern/d 删除匹配pattern的行 /pattern/s/pattern1/pattern2/ 查找符合pattern的行将该行第一个匹配pattern1的字符串替换为pattern2 /pattern/s/pattern1/pattern2/g 查找符合pattern的行将该行所有匹配pattern1的字符串替换为pattern2 使用p命令需要注意sed是把待处理文件的内容连同处理结果一起输出到标准输出的因此p命令表示除了把文件内容打印出来之外还额外打印一遍匹配pattern的行。 比如一个文件testfile的内容是 123 abc 456 123打印其中包含abc的行 $ sed /abc/p testfile 123 abc abc 456 12345要想只输出处理结果应加上-n选项这种用法相当于grep命令 $ sed -n /abc/p testfile abc 12使用d命令就不需要-n参数了比如删除含有abc的行 $ sed /abc/d testfile 123 456 123注意sed命令不会修改原文件删除命令只表示某些行不打印输出而不是从原文件中删去。 使用查找替换命令时可以把匹配pattern1的字符串复制到pattern2中比如 $ sed s/bc/--/ testfile 123 a-bc- 456 1234pattern2中的表示原文件的当前行中与pattern1相匹配的字符串 再比如 $ sed s/\([0-9]\)\([0-9]\)/-\1-~\2~/ testfile -1-~2~3 abc -4-~5~6 1234pattern2中的\1表示与pattern1的第一个()括号相匹配的内容\2表示与pattern1的第二个()括号相匹配的内容。sed默认使用Basic正则表达式规范如果指定了-r选项则使用Extended规范那么()括号就不必转义了。如 sed -r s/([0-9])([0-9])/-\1-~\2~/ out.sh 1替换结束后所有行含有连续数字的第一个数字前后都添加了“-”号第二个数字前后都添加了“~”号。 可以一次指定多条不同的替换命令用“;”隔开 $ sed s/yes/no/;s/static/dhcp/ ./testfile 1注使用分号隔开指令。 也可以使用 -e 参数来指定不同的替换命令有几个替换命令需添加几个 -e 参数 $ sed -e s/yes/no/ -e s/static/dhcp/ testfile 1注使用-e选项。 如果testfile的内容是 htmlheadtitleHello World/title/head bodyWelcome to the world of regexp!/body/html 12现在要去掉所有的HTML标签使输出结果为 Hello World Welcome to the world of regexp! 12怎么做呢如果用下面的命令 $ sed s/.*//g testfile 1结果是两个空行把所有字符都过滤掉了。这是因为正则表达式中的数量限定符会匹配尽可能长的字符串这称为贪心的(Greedy)。比如sed在处理第一行时.*匹配的并不是或这样的标签而是 htmlheadtitleHello World/title 1这样一整行因为这一行开头是中间是若干个任意字符末尾是。那么这条命令怎么改才对呢 awk sed以行为单位处理文件awk比sed强的地方在于不仅能以行为单位还能以列为单位处理文件。 awk缺省的行分隔符是换行缺省的列分隔符是连续的空格和Tab但是行分隔符和列分隔符都可以自定义比如/etc/passwd文件的每一行有若干个字段字段之间以:分隔就可以重新定义awk的列分隔符为:并以列为单位处理这个文件。 awk实际上是一门很复杂的脚本语言还有像C语言一样的分支和循环结构但是基本用法和sed类似awk命令行的基本形式为 awk option ‘script’ file1 file2 … awk option -f scriptfile file1 file2 … 和sed一样awk处理的文件既可以由标准输入重定向得到也可以当命令行参数传入编辑命令可以直接当命令行参数传入也可以用-f参数指定一个脚本文件编辑命令的格式为 /pattern/{actions} condition{actions} 和sed类似pattern是正则表达式actions是一系列操作。 awk程序一行一行读出待处理文件如果某一行与pattern匹配或者满足condition条件则执行相应的actions如果一条awk命令只有actions部分则actions作用于待处理文件的每一行。 比如文件testfile的内容表示某商店的库存量 ProductA 30 ProductB 76 ProductC 55 123打印每一行的第二列: $ awk {print $2;} testfile 30 76 55 1234自动变量$1、$2分别表示第一列、第二列等类似于Shell脚本的位置参数而$0表示整个当前行。再比如如果某种产品的库存量低于75则在行末标注需要订货 $ awk $275 {printf %s\t%s\n, $0, REORDER;} $275 {print $0;} testfile ProductA 30 REORDER ProductB 76 ProductC 55 REORDER 1234可见awk也有和C语言非常相似的printf函数。 awk命令的condition部分还可以是两个特殊的conditionBEGIN和END对于每个待处理文件BEGIN后面的actions在处理整个文件之前执行一次END后面的actions在整个文件处理完之后执行一次。 awk命令可以像C语言一样使用变量但不需要定义变量比如统计一个文件中的空行数 $ awk /^ *$/ {xx1;} END {print x;} testfile 1就像Shell的环境变量一样有些awk变量是预定义的有特殊含义的 awk常用的内建变量 FILENAME 当前输入文件的文件名该变量是只读的 NR 当前行的行号该变量是只读的R代表record NF 当前行所拥有的列数该变量是只读的F代表field OFS 输出格式的列分隔符缺省是空格 FS 输入文件的列分融符缺省是连续的空格和Tab ORS 输出格式的行分隔符缺省是换行符 RS 输入文件的行分隔符缺省是换行符 例如打印系统中的用户帐号列表 $ awk BEGIN {FS:} {print $1;} /etc/passwd 1awk也可以像C语言一样使用if/else、while、for控制结构。可自行扩展学习。 C程序中使用正则 POSIX规定了正则表达式的C语言库函数详见regex(3)。我们已经学习了很多C语言库函数的用法读者应该具备自己看懂man手册的能力了。 本章介绍了正则表达式在grep、sed、awk中的用法学习要能够举一反三请读者根据regex(3)自己总结正则表达式在C语言中的用法写一些简单的程序例如验证用户输入的IP地址或email地址格式是否正确。 C语言处理正则表达式常用的函数有regcomp()、regexec()、regfree()和regerror()一般分为三个步骤如下所示 C语言中使用正则表达式一般分为三步 编译正则表达式 regcomp() 匹配正则表达式 regexec() 释放正则表达式 regfree() 下边是对三个函数的详细解释 这个函数把指定的正则表达式pattern编译成一种特定的数据格式compiled这样可以使匹配更有效。 函数regexec 会使用这个数据在目标文本串中进行模式匹配。执行成功返回。 int regcomp (regex_t *compiled, const char *pattern, int cflags) 1 regex_t 是一个结构体数据类型用来存放编译后的正则表达式它的成员re_nsub 用来存储正则表达式中的子正则表达式的个数子正则表达式就是用圆括号包起来的部分表达式。 pattern 是指向我们写好的正则表达式的指针。 cflags 有如下4个值或者是它们或运算(|)后的值 REG_EXTENDED 以功能更加强大的扩展正则表达式的方式进行匹配。 REG_ICASE 匹配字母时忽略大小写。 REG_NOSUB 不用存储匹配后的结果,只返回是否成功匹配。如果设置该标志位那么在regexec将忽略nmatch和pmatch两个参数。 REG_NEWLINE 识别换行符这样’$’就可以从行尾开始匹配’^’就可以从行的开头开始匹配。 当我们编译好正则表达式后就可以用regexec 匹配我们的目标文本串了如果在编译正则表达式的时候没有指定cflags的参数为REG_NEWLINE则默认情况下是忽略换行符的也就是把整个文本串当作一个字符串处理。 执行成功返回。 regmatch_t 是一个结构体数据类型在regex.h中定义 typedef struct {regoff_t rm_so;regoff_t rm_eo; } regmatch_t; 1234成员rm_so 存放匹配文本串在目标串中的开始位置rm_eo 存放结束位置。 通常我们以数组的形式定义一组这样的结构。因为往往我们的正则表达式中还包含子正则表达式。 数组0单元存放主正则表达式位置后边的单元依次存放子正则表达式位置。 int regexec (regex_t *compiled, char *string, size_t nmatch, regmatch_t matchptr[], int eflags) 1 compiled 是已经用regcomp函数编译好的正则表达式。 string 是目标文本串。 nmatch 是regmatch_t结构体数组的长度。 matchptr regmatch_t类型的结构体数组存放匹配文本串的位置信息。 eflags 有两个值: REG_NOTBOL 让特殊字符^无作用 REG_NOTEOL 让特殊字符无作用 当我们使用完编译好的正则表达式后或者要重新编译其他正则表达式的时候我们可以用这个函数清空compiled指向的regex_t结构体的内容请记住如果是重新编译的话一定要先清空regex_t结构体。 void regfree (regex_t *compiled) 1当执行regcomp 或者regexec 产生错误的时候就可以调用这个函数而返回一个包含错误信息的字符串。 size_t regerror (int errcode, regex_t *compiled, char *buffer, size_t length) 1 errcode 是由regcomp 和 regexec 函数返回的错误代号。 compiled 是已经用regcomp函数编译好的正则表达式这个值可以为NULL。 buffer 指向用来存放错误信息的字符串的内存空间。 length 指明buffer的长度如果这个错误信息的长度大于这个值则regerror 函数会自动截断超出的字符串但他仍然会返回完整的字符串的长度。 所以我们可以用如下的方法先得到错误字符串的长度。 例如 size_t length regerror (errcode, compiled, NULL, 0); 测试用例 #include sys/types.h #include regex.h #include stdio.hint main(int argc, char ** argv) {if (argc ! 3) {printf(Usage: %s RegexString Text\n, argv[0]);return 1;}const char * pregexstr argv[1];const char * ptext argv[2];regex_t oregex;int nerrcode 0;char szerrmsg[1024] {0};size_t unerrmsglen 0;if ((nerrcode regcomp(oregex, pregexstr, REG_EXTENDED|REG_NOSUB)) 0) {if ((nerrcode regexec(oregex, ptext, 0, NULL, 0)) 0) {printf(%s matches %s\n, ptext, pregexstr);regfree(oregex);return 0;}}unerrmsglen regerror(nerrcode, oregex, szerrmsg, sizeof(szerrmsg));unerrmsglen unerrmsglen sizeof(szerrmsg) ? unerrmsglen : sizeof(szerrmsg) - 1;szerrmsg[unerrmsglen] \0;printf(ErrMsg: %s\n, szerrmsg);regfree(oregex);return 1; } 12345678910111213141516171819202122232425262728293031匹配网址 ./a.out http:\/\/www\..*\.com http://www.taobao.com 1匹配邮箱 ./a.out ^[a-zA-Z0-9][a-zA-Z0-9].[a-zA-Z0-9] c01cpp123c01cpp.com ./a.out \w([-.]\w)*\w([-.]\w)*\.\w([-.]\w)* c01cppqq.com 12注\w匹配一个字符包含下划线 匹配固话号码请同学们自己编写。 除了gnu提供的函数外还常用PCRE处理正则全称是Perl Compatible Regular Ex-pressions。 从名字我们可以看出PCRE库是与Perl中正则表达式相兼容的一个正则表达式库。 PCRE是免费开源的库它是由C语言实现的这里是它的官方主页http://www.pcre.org/感兴趣的朋友可以在这里了解更多的内容。 要得到PCRE库可以从这里下载http://sourceforge.net/projects/pcre/files/ PCRE是一个对PCRE库的C封装它提供了更加方便、易用的C接口。 这里是它的官方主页http://www.daemon.de/PCRE感兴趣的朋友可以在这里了解更多的内容。 要得到PCRE库可以从这里下载http://www.daemon.de/PcreDownload 另外c中常用 boost regex。 习题训练 1.求2个数之和 2. 计算1-100的和 3. 将一目录下所有的文件的扩展名改为bak 4. 编译当前目录下的所有.c文件 5. 打印root可以使用可执行文件数处理结果: root’s bins: 2306 6. 打印当前sshd的端口和进程id处理结果: sshd Portpid: 22 5412 7. 输出本机创建20000个目录所用的时间处理结果: real 0m3.367s user 0m0.066s sys 0m1.925s 8. 打印本机的交换分区大小处理结果: Swap:1024M 9. 文本分析取出/etc/password中shell出现的次数 第一种方法结果: 4 /bin/bash 1 /bin/sync 1 /sbin/halt 31 /sbin/nologin 1 /sbin/shutdown 第二种方法结果: /bin/sync 1 /bin/bash 1 /sbin/nologin 30 /sbin/halt 1 /sbin/shutdown 1 10.文件整理employee文件中记录了工号和姓名, bonus文件中记录工号和工资要求把两个文件合并并输出如下处理结果:提示join 400 ashok sharma 1,250100jasonsmith1,250100jasonsmith 5,000 200 john doe 500300sanjaygupta500300sanjaygupta 3,000 employee.txt: 100 Jason Smith 200 John Doe 300 Sanjay Gupta 400 Ashok Sharma bonus.txt: 100 $5,000 200 $500 300 $3,000 400 $1,250 1234567891011.写一个shell脚本来得到当前的日期时间用户名和当前工作目录。 12. 编写shell脚本获取本机的网络地址。 13. 编写个shell脚本将当前目录下大于10K的文件转移到/tmp目录下 14. 编写一个名为myfirstshell.sh的脚本它包括以下内容。 a) 包含一段注释列出您的姓名、脚本的名称和编写这个脚本的目的。 b) 问候用户。 c) 显示日期和时间。 d) 显示这个月的日历。 e) 显示您的机器名。 f) 显示当前这个操作系统的名称和版本。 g) 显示父目录中的所有文件的列表。 h) 显示root正在运行的所有进程。 i) 显示变量TERM、PATH和HOME的值。 j) 显示磁盘使用情况。 k) 用id命令打印出您的组ID。 m) 跟用户说“Good bye” 15.文件移动拷贝有m1.txt m2.txt m3.txt m4.txt分别创建出对应的目录m1 m2 m3 m4 并把文件移动到对应的目录下。 16. root用户今天登陆了多长时间 17. 终端输入一个文件名判断是否是设备文件 18. 统计IP访问要求分析apache访问日志找出访问页面数量在前100位的IP数。日志大小在78M左右。以下是apache的访问日志节选 202.101.129.218 - - [26/Mar/2006:23:59:55 0800] “GET /online/stat_inst.php?pidd065 HTTP/1.1” 302 20-“-” “-” “Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1)” 19.设计一个Shell程序在/userdata目录下建立50个目录即user1user50并设置每个目录的权限其中其他用户的权限为读文件所有者的权限为读、写、执行文件所有者所在组的权限为读、执行。 20. 设计一个shell程序添加一个新组为class1然后添加属于这个组的30个用户用户名的形式为stdxx其中xx从01到30并设置密码为对应的stdxx。 21. 编写shell程序实现自动删除30个账号的功能。账号名为std01至std30。 22. 用户清理,清除本机除了当前登陆用户以外的所有用户 23. 设计一个shell程序在每月第一天备份并压缩/etc目录的所有内容存放在/root/bak目录里且文件名,为如下形式yymmdd_etcyy为年mm为月dd为日。Shell程序fileback存放在/usr/bin目录下。 24. 对于一个用户日志文件每行记录了一个用户查询串长度为1-255字节共几千万行请排出查询最多的前100条。 日志可以自己构造 。 (提示awk sort uniq head) 25. 编写自己的ubuntu环境安装脚本 26. 编写服务器守护进程管理脚本。 转载于:https://www.cnblogs.com/powerwu/articles/9712455.html
http://www.pierceye.com/news/872262/

相关文章:

  • 蓝色系网站设计企业应对承包商的施工方案尤其是
  • 旅游网站 源码 织梦导购网站开发
  • 头像制作网站开源低代码平台
  • 网站到期域名怎么解决办法自己动手建立网站3
  • 比较有名的网站建设平台吉林建设网站
  • 网站服务器解决方案wamp安装wordpress
  • 义乌制作网站赣州网站建设公司
  • 东莞网站平台后缀建设淘宝客网站
  • 深圳龙华新区住房和建设局网站示范校建设专题网站
  • 成都制作网站的公司简介wordpress录入表单写数据库
  • 中山网站设计收费标准互联网保险发展现状和趋势
  • 公司网站发布流程简述企业网络建设的步骤
  • 哪些网站可以做问卷第1063章 自己做视频网站
  • 电子商务网站 费用做p2p网站
  • 网站建设 猴王网络厦门app开发网站开发公司电话
  • 做3d图的网站有哪些比wordpress更好的网站程序
  • 仿做网站可以整站下载器吧网络网站建设公司
  • 网站流量用完wordpress page 父页面
  • 旅游地网站制作有没有做网站的高手
  • 有什么网站可以做一起作业什么网站可以兼职做效果图
  • 工程中标查询网站长沙网站制作作
  • 免费网站下载直播软件企业品牌网站建设类型
  • 建立网站并以此为基础从事经营活动的企业称为什么免费销售网站模板
  • 成都市建设质监站网站微信企业网站html5模板
  • 福建工程建设管理中心网站仙桃做企业网站的
  • 孝感做网站的公司建网站是永久的吗
  • 厦门手机建站php网站开发推荐书籍
  • 属于c2c网站的有哪几个方庄网站制作
  • 建设局网站模板iis 网站没有上传权限
  • 建设网站龙华怎么用自己的电脑搭建网站