如果模式在下一行,则使用sed替换行

时间:2014-07-11 09:05:57

标签: sed

如何让sed替换上一行?我只遇到了deleteinsert行的示例,但实际上我需要的是,只有满足跟随行的条件时才会替换当前行。< / p>

我的示例文件是这样的

$ /bin/cat test
Cygwin
Cygwin is a cool emulator for Linux on Windows.

Unix
Maybe
the coolest environment?

Linux
Is also one of the best environments
Solaris
Why did Sun feel copying Java into Unix would matter?

AIX
Unknown

我期望的输出如下。将:::前置到具有最多25个字符的字符串,但前提是 next 行上的字符串长度超过25个字符。因此,下面有UnixAIX的行不应该以{{1​​}}为前缀,但其他人会这样做。

:::

$ # See detailed sed expression in my answer below :::Cygwin Cygwin is a cool emulator for Linux on Windows. Unix Maybe the coolest environment? :::Linux Is also one of the best environments :::Solaris Why did Sun feel copying Java into Unix would matter? AIX Unknown 表达式可以帮助我做到这一点?

我倾向于只使用sed,因为这是其他一些脚本的一部分,其他sed表达式正在进行中,所以我想要偏离if可能的。

4 个答案:

答案 0 :(得分:1)

这里有一个sed表达式,它为我提供了我想要的输出,

/bin/sed -rne '/^\s*$/{d;};{p;}' test | /bin/sed -rne '/(^.{5,26}$)/{$p;h;n;/^.{5,26}$/{x;p;x;p;D;};{x;s/(^.*$)/:::\1/;p;x;p;D;}};{$p;h;p;}'

具体来说,下面两个sed个表达式一起输出,

/bin/sed -rne '/^\s*$/{d;};{p;}' test 
# Remove any empty-lines (optionally containing spaces)

/bin/sed -rne  '/(^.{5,26}$)/{$p;h;n;/^.{5,26}$/{x;p;x;p;D;};{x;s/(^.*$)/:::\1/;p;x;p;D;}};{$p;h;p;}'
# This is the killer sed expression I came up with hunting around with my limited knowledge

# The detailed breakdown of this expression is as below,
/(^.{5,26}$)/ # Get a string of characters atleast 5 chars to max 26 chars
{
 $p; # Print if it's already on last line (since -n is in effect)
 h; # Save it to hold space
 n; # Get the next line into pattern space
  /^.{5,26}$/ # Check if pattern space (i.e. next line) also has min 5, max 26 chars
    { # if above condition passed, execute inside here
      x; # Swap pattern with hold space; i.e. Get current line back
      p; # Print it (i.e. the first line)
      x; # Swap again; to get back next line
      p; # Print it (i.e. the second line)
      D; # Stop cycle here, and process the next line in the input file
    };
    { # else block for above if-condition
      x; # Swap pattern with hold space; i.e. Get current line back
      s/(^.*$)/:::\1/; # Append ::: in front of line
      p; # Print it (i.e. the first line)
      x; # Swap again; to get back next line
      p; # Print it (i.e. the second line)
      D; # Stop cycle here, and process the next line in the input file
     } # End processing next line
  } # End if match
{ # Current line is longer than max 26 chars,
  $p; # Print if it's already on last line (since -n is in effect)
  h; # Remember it in hold space
  p; # Print it (i.e. the current line)
}

通过以上解释,我能够实现我的需要。

但我仍然不相信这是不是可以用简洁或更好的方式编写或解释?

答案 1 :(得分:1)

awk如果你厌倦了尝试在这个特殊的螺丝上使用sed的锤子,这很简单: - )

awk '{x[NR]=$0} END{for(i=1;i<=NR;i++){if(length(x[i])<26 && length(x[i+1])>25)printf ":::";print x[i]}}' file

保存数组x[]中的所有行。最后,遍历打印它们的行,但前缀符合条件的行:::

答案 2 :(得分:1)

这可能适合你(GNU sed):

sed -r '$!N;/^.{1,25}\n.{26,}$/s/^/:::/;P;D' file

答案 3 :(得分:0)

来自命令行的Perl One-Liner

这个perl单行将会做到(刚刚测试):

perl -0777 -pe 's/^([^\n]{1,25}$)(?=\n[^\n]{25,}$)/:::$1/smg' yourfile