简体   繁体   English

用sed有条件地替换字符串片段(单线!)

[英]Conditional replacement of string fragment with sed (one-liner!)

I am trying to process the result of diff operation with sed . 我正在尝试使用sed处理差异操作的结果。 This is my diff output, which I pipe into sed 这是我的差异输出,我通过管道输出到sed

3d2
< 12-03-22_JET_D_CL_UR_l4053_0061 True_Warning All 9 149261 
62a62
> 13-01-29_VUE_EPM3_v37_CSAV2_0370 True_Warning All 13 22125 
68c68
< 13-05-14_Regular_Front_0062 True_Warning All 13 123383 
---
> 13-05-14_Regular_Front_0062 True_Warning All 21 123383 
119c119
< CADS4_PMP363_20130202_DPH_069 True_Warning All 13 233405 
---
> CADS4_PMP363_20130202_DPH_069 True_Warning All 9 233409 
149c149
< CADS4_PMP363_20130315_Fujifilm_UK_186 True_Warning All 21 18611 
---
> CADS4_PMP363_20130315_Fujifilm_UK_186 True_Warning All 17 18615 

I need to sort out the difference string and prepend the 3rd word in the strings with either "Old" or "New" - depending on the first character. 我需要整理差异字符串,并在字符串中的第三个单词前加上“旧”或“新”-取决于第一个字符。 My best effort so far is 到目前为止,我最大的努力是

diff new_jumps/true.jump old_jumps/true.jump | sed -n "/^[<>]/ s:\(.\) \(\S\+\) \(.\+\):\2 \1,\3: p" | replace ">" Old | replace "<" New

Which give me this result (exactly what I wanted). 这给了我这个结果(正是我想要的)。

12-03-22_JET_D_CL_UR_l4053_0061 New,True_Warning All 9 149261 
13-01-29_VUE_EPM3_v37_CSAV2_0370 Old,True_Warning All 13 22125 
13-05-14_Regular_Front_0062 New,True_Warning All 13 123383 
13-05-14_Regular_Front_0062 Old,True_Warning All 21 123383 
CADS4_PMP363_20130202_DPH_069 New,True_Warning All 13 233405 
CADS4_PMP363_20130202_DPH_069 Old,True_Warning All 9 233409 
CADS4_PMP363_20130315_Fujifilm_UK_186 New,True_Warning All 21 18611 
CADS4_PMP363_20130315_Fujifilm_UK_186 Old,True_Warning All 17 18615 

My question is - how can I change conditional expression within sed one-liner that will eliminate the need to use replace afterwards? 我的问题是-我该如何在sed单线内更改条件表达式,从而消除以后再使用replace的需要? (I assume that it is possible) Thanks in advance (我认为有可能)在此先感谢

EDIT: 编辑:

I know, I missed the option to chain sed expressions, but what I had in mind - is it possible to do it within one substitute operation ? 我知道,我错过了链接sed表达式的选项,但是我想到的是-是否可以在一个替代操作中完成它?

通过使用分号(;)向sed添加更多命令,如下所示:

diff new_jumps/true.jump old_jumps/true.jump | sed -n "/^[<>]/ s:\(.\) \(\S\+\) \(.\+\):\2 \1,\3:; s/</New/gp; s/>/Old/gp"

With awk I get a faster response. 使用awk,我得到更快的响应。 Try this: 尝试这个:

diff new_jumps/true.jump old_jumps/true.jump | awk '{ if($1=="<" || $1==">"){($1=="<")?temp="New,":temp="Old,";print $2,temp$3,$4,$5}}'

Here's another solution suggested by Jidder: 这是Jidder建议的另一种解决方案:

awk '/^</{i="old,"}/^>/{i="new,"}i{$2=$2" "i;print;i=0}'

@volcano: here is a one-liner solution in sed, but relies in the interaction with the shell. @volcano:这是sed中的单线解决方案,但依赖于与外壳的交互。 IMHO if you want to have only one sed substitution command, you cannot avoid that behavior: you have to output to the shell the information of which first character has been seen on the line, the shell somewhat does the mapping to "Old" or "New" strings, and gives the result back to sed. 恕我直言,如果您只想使用一个sed替换命令,那么您将无法避免这种行为:您必须向shell输出在行中看到第一个字符的信息,shell会稍微映射到“ Old”或“新”字符串,并将结果返回给sed。

So the one-liner is not exactly a one-liner because we have to define things in the shell... ;) 因此,单线不完全是单线,因为我们必须在外壳中定义事物...;)

replace() { if [ "$1" == ">" ] ; then echo -n "Old"; else echo -n "New" ; fi }
export -f replace
sed -n '/^[<>]/ s:\(.\) \(\S\+\) \(.\+\):echo "\2 $(replace \\\1),\3";:ep' yourfile

Please note that the e flag to the substitution command is a GNU sed extension, we use it here to avoid calling the shell explicitly. 请注意,替换命令的e标志是GNU sed扩展,我们在这里使用它以避免显式调用shell。 If you don't use GNU sed, you can simply replace the last line above by the following: 如果您不使用GNU sed,则只需将下面的最后一行替换为以下内容:

sed -n '/^[<>]/ s:\(.\) \(\S\+\) \(.\+\):echo "\2 $(replace \\\1),\3";:p' yourfile | bash

The solution I am giving here has been inspired by that other one . 我在这里给出的解决方案受到了另一个启发。

Please also note that all this gymnastics is avoidable if you accept to replace your three-letter tokens "Old" and "New" by their initials, because then we can neatly use the y command to first act in a tr fashion, likewise: 还请注意,如果您接受将三个字母的标记“ Old”和“ New”替换为首字母缩写,那么所有这些体操活动都是可以避免的,因为这样我们就可以巧妙地使用y命令首先以tr方式进行操作,同样:

sed -n '/^[<>]/ y/<>/ON/; s:\(.\) \(\S\+\) \(.\+\):\2 \1,\3:p' yourfile

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM