84669 人が学習中
152542 人が学習中
20005 人が学習中
5487 人が学習中
7821 人が学習中
359900 人が学習中
3350 人が学習中
180660 人が学習中
48569 人が学習中
18603 人が学習中
40936 人が学習中
1549 人が学習中
1183 人が学習中
32909 人が学習中
如果第1行和第2行都不以;开头,则合并这两行为新行,并继续处理新行和第3行; 如果第1行以;开头,则继续处理第2行和第3行。 以上流程仅为方便描述,只要能达到相同效果即可。 如输入为: ;a ;;b c d; e;;; ;f g 期望输出: ;a ;;b cd;e;;; ;f g
学习是最好的投资!
awk '!/^;/{a=a$0}/^;/{if(a!="")print a;print $0;a="";}END{if(a!="")print a;}'
awk语法 test1{statements1}test2{statements2}...
test1{statements1}test2{statements2}...
针对每一行,如果满足test1,则执行statement1,如果满足test2,则执行statement2 ...
每一行
所以分3部分:
!/^;/{a=a$0}
;
a
!/^;/
!
/.../
^;
a=a$0
$0
a$0
/^;/{if(a!="")print a;print $0;a="";}
/^;/
if(a!="")print a;print $0;a="";
if(a!="")print a;
print $0;
a="";
END{if(a!="")print a;}
END
BEGIN
首先: 将换行符去掉,/\n//g 然后: 判断字母序列右侧是否有数字,有则在右侧添加换行符/([a-z]+)(?=[0-9]+)/\1\/n/g 判断字母序列左侧是否有数字,有则在左侧添加换行符/([a-z]+)(?<=[0-9]+)/\/n\1/g 最后: 将上面正则表达式用sed或者awk实现。
/\n//g
/([a-z]+)(?=[0-9]+)/\1\/n/g
/([a-z]+)(?<=[0-9]+)/\/n\1/g
sed
awk
awk版本
awk '$0 !~ /^;/{a=a$0;}/^;/{print a?a"\n"$0:$0;a=""}END{if(a)print a}' urfile
再附加一个sed的
sed -n '/^;/{H;x;s/^\n//g;p;s/.*//g;x;};/^;/!{H;x;s/\n//g;x};${/^;/!p}' urfile
这种略复杂的需求,用sed/awk是可以实现,但是我觉得不推荐,这时候一般用python或者perl来做更高效。
不过为了看看我的sed功底还在不在,还是尝试了一下,目前简单测试没有发现问题,代码如下:
sed -r -n '/^;/!{h;s/.*//;x;:l $!{H;n;/^;/!b l};x;s/\n//gp;g};p'
解释几个重点的部分: 1. h;s/.*//;x;是为了清空hold space 2. :l $!{H;n;/^;/!b l};部分是一个循环,将所有的非;开头的行合并到hold space,退出条件有两个:到达最后一行或者遇到一个;开头的行 3. x;s/\n//gp;g 将hold space中的内容去掉换行符并打印出来 4. 最后p打印pattern space中的内容,用来打印;开头的行
h;s/.*//;x;
:l $!{H;n;/^;/!b l};
x;s/\n//gp;g
p
答案还没写完,发现一个bug了: 如果文件的末尾有2行以上的非;开头的行,最后一行没有被合并。
修改一下原来的答案为:
sed -r -n '/^;/!{h;s/.*//;x;:l $!{H;n;/^;/!b l};/^;/!{H;g;s/\n//gp;t};x;s/\n//gp;g};p'
修改说明: 1. 跳出循环之后,判断当前行如果不是;开头(根据之前的跳出条件可知,这是最后一行),将当前行加入hold space,然后处理hold space的内容
看吧,一个其实也不是很复杂的需求,用sed来写,命令越写越长,1个月后还能一眼看懂么?这类需求还是不要用sed来做了吧
答案
解释
awk语法
test1{statements1}test2{statements2}...
针对
每一行
,如果满足test1,则执行statement1,如果满足test2,则执行statement2 ...所以分3部分:
!/^;/{a=a$0}
如果不以;
开头,则将当前行追加到临时变量a
(作为缓冲区)中!/^;/
!
否定/.../
表示测试当前行是否满足给定正则表达式^;
正则表达式,表示以;
开头a=a$0
a
变量,无需声明,直接使用,默认值是0、null、"",根据使用场景自动转换,这里第一次用就是空字符串$0
表示整个一行的内容a$0
两个字符串写在一起,表示字符串拼接/^;/{if(a!="")print a;print $0;a="";}
如果以;
开头,先输出临时拼接的变量a
(若有),再输出当前行/^;/
判断当前行是否以;
开头if(a!="")print a;print $0;a="";
if(a!="")print a;
如果a不为空,则输出a的值(print自动换行)print $0;
打印当前行a="";
清空a
的值,以备下次使用END{if(a!="")print a;}
处理完所有行,最后再判断缓冲区a
中是否有内容,若有,则打印;
开头,会全部追加到a
中,一直没有机会输出出来,因为碰到;
开头的行才会输出END
条件表示处理完最后一行之后(相对的当然有BEGIN
,表示处理第一行之前)首先: 将换行符去掉,
/\n//g
然后: 判断字母序列右侧是否有数字,有则在右侧添加换行符
/([a-z]+)(?=[0-9]+)/\1\/n/g
判断字母序列左侧是否有数字,有则在左侧添加换行符
/([a-z]+)(?<=[0-9]+)/\/n\1/g
最后: 将上面正则表达式用
sed
或者awk
实现。awk版本
再附加一个sed的
这种略复杂的需求,用sed/awk是可以实现,但是我觉得不推荐,这时候一般用python或者perl来做更高效。
不过为了看看我的sed功底还在不在,还是尝试了一下,目前简单测试没有发现问题,代码如下:
解释几个重点的部分:
1.
h;s/.*//;x;
是为了清空hold space2.
:l $!{H;n;/^;/!b l};
部分是一个循环,将所有的非;
开头的行合并到hold space,退出条件有两个:到达最后一行或者遇到一个;
开头的行3.
x;s/\n//gp;g
将hold space中的内容去掉换行符并打印出来4. 最后
p
打印pattern space中的内容,用来打印;
开头的行答案还没写完,发现一个bug了: 如果文件的末尾有2行以上的非
;
开头的行,最后一行没有被合并。修改一下原来的答案为:
修改说明:
1. 跳出循环之后,判断当前行如果不是
;
开头(根据之前的跳出条件可知,这是最后一行),将当前行加入hold space,然后处理hold space的内容看吧,一个其实也不是很复杂的需求,用sed来写,命令越写越长,1个月后还能一眼看懂么?这类需求还是不要用sed来做了吧