【问题标题】:Conditional replacement of string fragment with sed (one-liner!)用 sed 有条件地替换字符串片段(单行!)
【发布时间】:2014-07-03 07:55:15
【问题描述】:

我正在尝试用 sed 处理 diff 操作的结果。这是我的 diff 输出,我通过管道将其输入 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 

我需要整理出差异字符串,并在字符串中的第三个单词前面加上“Old”或“New” - 取决于第一个字符。到目前为止,我最大的努力是

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

这给了我这个结果(正是我想要的)。

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 

我的问题是 - 如何更改 sed 单行中的条件表达式,以消除之后使用 replace 的需要? (我认为这是可能的) 提前致谢

编辑:

我知道,我错过了链接 sed 表达式的选项,但我的想法是 - 是否有可能在一个替代操作中

【问题讨论】:

    标签: bash sed tcsh


    【解决方案1】:

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

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

    【讨论】:

      【解决方案2】:

      使用 awk 我得到了更快的响应。试试这个:

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

      这是 Jidder 建议的另一种解决方案:

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

      【讨论】:

      • 插入了更好的解决方案
      • @volcano 这留下了前面的&lt; &gt; 这就是你想要的吗?
      • 谢谢,我可能会用它
      • @Jidder,这不是火箭科学:)
      • @Volcano 是另一种方式:) awk '/^&lt;/{i="old,"}/^&gt;/{i="new,"}i{$2=$2" "i;print;i=0}'
      【解决方案3】:

      @volcano:这是 sed 中的单线解决方案,但依赖于与 shell 的交互。恕我直言,如果您只想使用一个 sed 替换命令,则无法避免这种行为:您必须向 shell 输出已在该行中看到的第一个字符的信息,shell 在某种程度上将映射到“旧”或“ New" 字符串,并将结果返回给 sed。

      所以单行并不完全是单行,因为我们必须在 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
      

      请注意,替换命令的 e 标志是 GNU sed 扩展,我们在这里使用它是为了避免显式调用 shell。如果您不使用 GNU sed,您可以简单地将上面的最后一行替换为以下内容:

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

      我在这里给出的解决方案受到that other one 的启发。

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

      【讨论】:

        猜你喜欢
        • 2011-10-03
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-07-28
        • 2020-03-13
        • 1970-01-01
        • 2021-06-21
        相关资源
        最近更新 更多