shell问题(转)
一个同学问我一个问题,说有以下文件内容,要求输出为特定的格式。这里就献丑给出一个处理的方法吧,由于时间关系可能我的答案并不是最好的,但是我尽量将我的答案讲解明白,让你理解处理的方法。如果您有简单明了的处理方法请不啬赐教!
|
题目 |
文件内容如下:
|
2016-12-08 00:09 血战钢锯岭 2016-12-08 03:01 你的名字 2016-12-08 04:00 长城 2016-12-08 04:01 萨利机长 2016-12-09 07:35 神奇动物在 2016-12-09 09:24 湄公河行动 2016-12-09 10:59 我不是潘金莲 2016-12-09 12:43 海洋奇缘 2016-12-09 14:29 神奇四侠2015 2016-12-10 16:30 死侍 2016-12-10 16:31 加勒比海盗5:死 2016-12-10 16:36 三体 2016-12-10 18:04 阿凡达2 2016-12-10 19:40 日落七次 |
要求输出结果为:
|
2016-12-08 00:09 血战钢锯岭 03:01 你的名字 04:00 长城 04:01 萨利机长 2016-12-09 07:35 神奇动物在 09:24 湄公河行动 10:59 我不是潘金莲 12:43 海洋奇缘 14:29 神奇四侠2015 2016-12-10 16:30 死侍 16:31 加勒比海盗5:死 16:36 三体 18:04 阿凡达2 19:40 日落七次 |
|
参考答案 |
看到题目后,发现文件内容中的规律,源文件主要由年月日、时分和电影名称组成三列,而目标文件年月日主要是去重,每个日期只出现了一次后换行,将当日要上映电影的时分和电影名称按行显示出来。
因为是文件处理,首先我想到了sed来处理,使用sed加正则表达式将文件内容进行分组处理,然后去除重复的“年月日”,实现代码如下:
|
# sed -r "s/([0-9]{4}-[0-9]{2}-[0-9]{2})(\t)(.*)(\t)(.*)/\1\n\3\t\5/" file |sed -r ':1;N;s/^(\S+)((\n.*)*)\n\1$/\1\2/M;$!b1' 2016-12-08 00:09 血战钢锯岭 03:01 你的名字 04:00 长城 04:01 萨利机长 2016-12-09 07:35 神奇动物在 09:24 湄公河行动 10:59 我不是潘金莲 12:43 海洋奇缘 2016-12-10 16:30 死侍 16:31 加勒比海盗5:死 16:36 三体 19:40 日落七次 # |
|
答案剖析 |
首先,我们先看管道前的代码,主要是将“年月日”和“时分,电影名称”分成了两部分。我们看到sed的-r选项的意思是支持扩展的这规则表达式,类似grep的-P。其中([0-9]{4}-[0-9]{2}-[0-9]{2})(\t)(.*)(\t)(.*)是正则表达式和分组。
正则表达式是指用来描述或者匹配一系列符合某个句法规则的字符串的单个字符串。就是用某种模式去匹配一类字符串的一个公式。Sed中的正则如下表所示:
|
^ |
行的开始 |
|
$ |
行的结尾 |
|
. |
一个字符 |
|
* |
匹配0个或多个*前面的字符 |
|
[] |
方括号中的所有字符 |
|
\ |
转义 |
|
{} |
重复次数 |
|
() |
分组,将匹配这个表达式的字符保存到一个临时区域(最多保存9个),它们可以用\1到\9来引用。 |
|
/./ |
匹配至少有一个字符 |
|
/../ |
匹配至少有两个字符的行 |
|
/^#/ |
匹配用#开头的行 |
|
/^$/ |
匹配空行 |
|
/}$/ |
匹配用}结尾的行(没有空格在后面) |
|
/} *$/ |
匹配用}结尾的行(可以有空格在后面) |
|
/[abc]/ |
匹配小写的a或b或c |
|
/^[^abc]/ |
匹配开头不是小写的a或b或c |
匹配该题目的正则表达式的含义如下:
·([0-9]{4}-[0-9]{2}-[0-9]{2}):匹配数字0-9重复4次,匹配年;匹配数字0-9重复2次匹配月和日,并使用()分组
·(\t):匹配制表符,如果你使用的空格分隔,直接匹配空格,可以使用(\ |\t)匹配空格或者制表符
·(.*):匹配任意字符
接下来解释演示/\1\n\3\t\5/的含义,为了减少篇幅,我复制一份文件名为file1,内容如下:
|
# cat file1 2016-12-08 00:09 血战钢锯岭 2016-12-08 03:01 你的名字 2016-12-09 10:59 我不是潘金莲 # |
执行如下命令,结果表明\1代表分组1,自然\3和\5代表分组3和5
|
# sed -r "s/([0-9]{4}-[0-9]{2}-[0-9]{2})(\ |\t)(.*)(\ |\t)(.*)/\1/" file1 2016-12-08 2016-12-08 2016-12-09 # |
那么\n代表什么呢?我们在现有命令上加上/n,结果表明\n代表换行,如下所示:
|
# sed -r "s/([0-9]{4}-[0-9]{2}-[0-9]{2})(\ |\t)(.*)(\ |\t)(.*)/\1\n/" file1 2016-12-08 2016-12-08 2016-12-09
# |
\t不用解释了吧,完整的执行以下如下所示:
|
# sed -r "s/([0-9]{4}-[0-9]{2}-[0-9]{2})(\ |\t)(.*)(\ |\t)(.*)/\1\n\3\t\5/" file1 2016-12-08 00:09 血战钢锯岭 2016-12-08 03:01 你的名字 2016-12-09 10:59 我不是潘金莲 # sed -r "s/([0-9]{4}-[0-9]{2}-[0-9]{2})(\ |\t)(.*)(\ |\t)(.*)/\1\n\3\t\5/" file1 >>file2 |
继续看管道后的命令的含义,之后的命令信息量有点稍微大。
|
# sed -r ':1;N;s/^(\S+)((\n.*)*)\n\1$/\1\2/M;$!b1' file2 2016-12-08 00:09 血战钢锯岭 03:01 你的名字 2016-12-09 10:59 我不是潘金莲 # |
主要有多行模式空间的操作命令N、D、P和sed脚本流程控制命令b、t。
多行模式空间(MultilinePattern Space):就是在模式空间中放置输入文件的多个行内容,操作多行模式空间的有N、D、P含义如下:
·N命令:是将下一行也输入到模式空间中,当前行与下一行之间插入一个’\n’,以下为示意图

·D命令:仅删除Multiline Space中第一个’\n’之前的内容,如上图,即删除“The UnixOperating System”,而“Is A interestingSystem”仍然存在。同时,它使得脚本的控制流转到脚本文件的第一行,跳过该命令的后续命令。
·P命令:仅打印Multiline Space中第一个’\n’之前的内容,如上图,即仅打印“The UnixOperating System”。
我们看下N的范例,还是使用file1文件中的内容,命令执行结果如下:
|
# sed ‘N’ file1 2016-12-08 00:09 血战钢锯岭 2016-12-08 03:01 你的名字 2016-12-09 10:59 我不是潘金莲 # |
看到结果后,有同学会说,这和Sed不加任何的选项和命令,执行的结果相同。如下所示:
|
# sed '' file1 2016-12-08 00:09 血战钢锯岭 2016-12-08 03:01 你的名字 2016-12-09 10:59 我不是潘金莲 # |
使用肉眼咋一看真发现不了区别,首先我们回顾下sed的工作过程:
sed会先读取文本中的第一行,到模式空间,然后执行sed命令,处理完成后,将结果发送到屏幕上。sed每处理完一行就将其从模式空间中删除,接着会读取文本中的第二行,到模式空间,然后执行sed命令,处理完成后,将结果发送到屏幕上。重复此过程,直到文本中的最后一行,sed便结束运行。
了解sed的工作原理,我们发现没有使用N命令时候,sed依次将文本中的行读取到模式空间中,sed没有做任何的命令操作,他就直接显示到屏幕上了。
当使用N命令后,sed执行过程是sed会先读取文本中的第一行 “2016-12-08 00:09 血战钢锯岭$”到模式空间,然后执行sed命令N,模式空间中的第一行内容后追加第二行内容生成多行模式空间的第一行内容,多行模式空间变为“2016-12-08 00:09 血战钢锯岭\n2016-12-08 03:01 你的名字$”,处理完成后,将结果发送到屏幕上。sed继续向模式空间读取下一行内容,本例中就是第三行,然后再次追加下一行内容,生成多行模式空间中的第二行内容,以此类推。由于本例中第三行下没有内容,这时候执行N命令后就不会生成多行模式空间的第二行内容,所以模式空间中有“2016-12-09 10:59 我不是潘金莲”。处理完成后,将结果发送到屏幕上。
结果表明,我们使用N命令后,前两行输出的是多行模式空间的内容,最后一行是模式空间的内容。由于多行模式空间合并的第一行和第二行之间有\n,所以看到输出的格式没有变化,为了证明这个说法,我们将\n 替换成空格,如下所示:
|
# sed 'N;s/\n/ /' file1 2016-12-08 00:09 血战钢锯岭 2016-12-08 03:01 你的名字 2016-12-09 10:59 我不是潘金莲 # |
通常,sed是将编辑命令从上到下依次应用到读入的行上,N命令能够在一定程序上改变默认的执行流程,甚至利用N命令可以形成一个强大的循环处理流程。除此之外,其实sed还提供了分支命令(b)和测试(test)两个命令来控制流程,这两个命令可以跳转到指定的标签(label)位置继续执行命令。标签是以冒号开头的标记,标签名称可以自定义。例如:定义一个名称为:label标签,如下所示:
|
:label command1 /pattern/b label command2 |
当执行到/pattern/b top时,如果匹配pattern,则跳转到:label标签所在的位置,继续执行下一个命令command1。
上面的例子用到了分支命令,分支命令的跳转是无条件的。而与之相对的是测试命令,测试命令的跳转是有条件的,当且仅当当前行发生成功的替换时才跳转。
为了明白测试命令的用法,我们用它来实现file1中的内容:
|
# sed -e ':1;s/2016/2017/;t1;' file1 2017-12-08 00:09 血战钢锯岭 2017-12-08 03:01 你的名字 2017-12-09 10:59 我不是潘金莲 # |
我们定义了一个标签为:1,然后在最后利用测试命令跳转到该标签。可能,你会觉得这里也可以使用分支命令,但是事实上分支命令会导致死循环,因为在它里他没有结束的条件。
但是测试命令就不同了,这一点直到最后才体现出来。当最后一行被s/2016/2017/命令读入之后,2016替换成2017,此时ta继续跳转到最开头,因为模式空间中的2016已经全部被替换成2017,所以替换也不会发生。之前我们说过,当且仅当当前行发生成功的替换时测试命令才跳转。所以此时跳转不会发生,退出sed命令。
到此,你能看明白后半句的意思吗?欢迎留言!
欢迎使用微信关注“运维爱好者”公共号,第一时间了解本博客动态!
shell问题(转)的更多相关文章
- Shell替换
如果表达式中包含特殊字符,Shell 将会进行替换.例如,在双引号中使用变量就是一种替换,转义字符也是一种替换. #!/bin/bash a= echo -e "Value of a is ...
- Shell特殊变量
$ 表示当前Shell进程的ID,即pid $echo $$ 运行结果 特殊变量列表 变量 含义 $0 当前脚本的文件名 $n 传递给脚本或函数的参数.n 是一个数字,表示第几个参数.例如,第一个参数 ...
- shell变量
定义变量 定义变量时,变量名不加美元符号($),如: variableName="value" 注意,变量名和等号之间不能有空格,这可能和你熟悉的所有编程语言都不一样.同时,变量名 ...
- 第一个shell脚本
打开文本编辑器,新建一个文件,扩展名为sh(sh代表shell),扩展名并不影响脚本执行,见名知意就好. #!/bin/bash echo "Hello World !" &quo ...
- shell简介
Shell作为命令语言,它交互式地解释和执行用户输入的命令:作为程序设计语言,它定义了各种变量和参数,并提供了许多在高级语言中才具有的控制结构,包括循环和分支. shell使用的熟练程度反映了用户对U ...
- Shell碎碎念
1. 字符串如何大小写转换 str="This is a Bash Shell script." 1> tr方式 newstr=`tr '[A-Z]' '[a-z]' < ...
- MongoDB学习笔记二—Shell操作
数据类型 MongoDB在保留JSON基本键/值对特性的基础上,添加了其他一些数据类型. null null用于表示空值或者不存在的字段:{“x”:null} 布尔型 布尔类型有两个值true和fal ...
- 使用C#给Linux写Shell脚本
在这个逼格决定人格,鄙视链盛行的年头,尤其是咱们IT界,请问您今天鄙视与被鄙视的次数分别是多少?如果手中没有一点压箱的本事,那就只有看的份了.今天我们也要提升下自己的格调,学习些脑洞大开的东西,学完之 ...
- Linux环境下shell和vim中乱码原因及消除办法
shell和vim中乱码原因及消除办法 作者:Jack47 在Linux下开发,经常遇到乱码问题:shell或者vim中显示不了中文,或者能够显示,但不能输入中文.每次都是上网去搜,或者同事告诉我一些 ...
- 【说解】在shell中通过mkfifo创建命名管道来控制多个进程并发执行
背景: 工作中有两个异地机房需要传数据,数据全名很规范,在某个目录下命名为统一的前缀加上编号.如/path/from/file.{1..100}.而机房间的专线对单个scp进程的传输速度是有限制的,比 ...
随机推荐
- windows服务相关
1. 卸载服务 cmd 命令: sc delete + 服务名 2. 注册服务 cmd 命令 : 服务名+ install 3.mysql 启动服务步骤 1) 初始化密码:mysqld -initi ...
- text-overflow:ellipsis
关键字: text-overflow:ellipsis 语法:text-overflow : clip | ellipsis 取值: clip :默认值 .不显示省略标记(...),而是简单的裁切. ...
- 【xsy1230】树
题意 \(N\)个点的树,边有边权.给\(M\)个询问,每个询问包含3个参数\(l,r,pos\),求标号在\(l\)到\(r\)中的所有点中,离节点pos最近的点到pos的距离. 分析:动态点分治+ ...
- 20145224&20145238《信息安全系统设计基础》实验三
20145224陈颢文20145238荆玉茗 <信息安全系统设计基础>第五次实验报告 课程:信息安全系统设计基础 班级: 1452 姓名:荆玉茗 陈颢文 学号:20145238 20145 ...
- windows docker安装方式的比较小结
稍微小结一下使用InstallDocker 和dockertoolbox的两种方式安装的docker(名称说明可能不妥,仅代表安装方式) InstallDocker 使用的是Microsoft Hy ...
- Windows Store App 关键帧动画
关键帧动画和插值动画类似,同样可以根据目标属性值的变化产生相应的动画效果,不同的是,插值动画是在两个属性值之间进行渐变,而关键帧动画打破了仅通过两个属性值控制动画的局限性,它可以在任意多个属性值之间进 ...
- 介绍开源的.net通信框架NetworkComms框架之五 心跳检测
原文网址: http://www.cnblogs.com/csdev Networkcomms 是一款C# 语言编写的TCP/UDP通信框架 作者是英国人 以前是收费的 目前作者已经开源 许可是 ...
- 学习di'z地址
Swift学习地址https://numbbbbb.gitbooks.io/-the-swift-programming-language-/content/ http://www.oschina.n ...
- ExtJs 4 中的MVC应用架构
一.ExtJs 4.x MVC模式的原理与作用 大规模客户端应用通常不好实现不好组织也不好维护,因为功能和人力的不断增加,这些应用的规模很快就会超出掌控能力,ExtJS4带来了一个新的应用架构,不但可 ...
- IT公司100题-32-交换元素,使数组差最小
问题描述: 有两个整数序列a, b,大小都为n, 序列元素的值任意整数,无序. 要求:通过交换a, b 中的元素,使得sum(a)-sum(b),差最小. 例如: var a=[80, 40, 60, ...