我想要转换:
A,p
B,q
C,r
D,s
进入:
A,p,q
B,q,r
C,r,s
使用sed
。
答案1
我怀疑sed
这不是什么问题(其他人可能知道如何用 做得更好sed
),但情况如下:
$ sed '2,$ s/.$/&,&/' file | sed -r ':a;N;s/\n(.)(,?.?)(,.)$/\3\n\1\2/;ta' | sed '$d'
A,p,q
B,q,r
C,r,s
笔记
sed '2,$ s/.$/&,&/'
表示复制除第一行之外的所有行的最后一个字符,并添加逗号:
2,$
从第二行开始s/old/new/
old
用。。。来代替new
.$
最后一个字符&
匹配的模式
sed -r ':a;N;s/\n(.)(,?.?)(,.)$/\3\n\1\2/;ta;'
意思是取出第一行之后每一行的最后一个字符,并将其粘贴到上一行的末尾:
-r
使用 ERE:a
标签:从这里执行;
分隔命令N
将下一行读入模式空间,以便我们可以用它\n
来表示模式中的换行符(.)
保存一个字符以供以后使用?
零个或一个前一个字符$
行结束\1
参考已保存的模式ta
如果最后一条s
命令成功,则分支:a
并再次执行循环$d
删除最后一行
如果您的文件的逗号之间不只有单个字符,您将无法使用上面非常简单的正则表达式。如果文件以逗号分隔,则这是一个有效的版本。例如,给定
January,apple
February,pear
March,kiwi
April,mango
你可以这样做,如果有的话,这也有效是当然只有一个字符
$ sed '2,$ s/[^,]*$/&,&/' file | sed -r ':a;N;s/\n([^,]*)(,?[^,]*)(,[^,]*)$/\3\n\1\2/;ta;' | sed '$d'
January,apple,pear
February,pear,kiwi
March,kiwi,mango
sed
;
脚本可以写在多行上。我不能说这显著提高了可读性;)但它可能更具可移植性,因为在非 GNU 版本的使用上有限制sed
:
sed '2,$ s/[^,]*$/&,&/' file |
sed -r '{:a
N
s/\n([^,]*)(,?[^,]*)(,[^,]*)$/\3\n\1\2/
ta}' |
sed '$d'
[^,]*
表示零个或多个不是逗号的字符。
答案2
我认为这是一种在单个 sed 调用中完成此操作的方法:
sed -nE '$!{:a;N;s/(.*)\n(.*)(,[^,]*$)/\1\3\n\2\3/;P;D;ba;}' file
A,p,q
B,q,r
C,r,s
解释
该:a;N;...P;D;ba
结构本质上维护一个双行缓冲区,我们可以在其中拆分字段并复制/移动字符组:
$!{ # For any line except the last
:a # Enter a loop:
N # Append the following line, after a newline
s/(.*)\n(.*)(,[^,]*)$/\1\3\n\2\3/ # Capture (1) up to the newline,
# (2) from the newline to the last comma,
# and (3) everything else into groups and
# copy group 3 before the newline
P # Print everything up to the newline
D # Delete everything up to the newline,
# ready for the next iteration
ba
}
请注意,使用-E
(或-r
)扩展正则表达式不是必需的 - 它只是减少所需的转义量。