【问题标题】:to check if a line before and after a string empty检查字符串前后的行是否为空
【发布时间】:2019-10-15 00:09:22
【问题描述】:

我需要删除所需文本之前的某些行数,但前提是搜索字符串之前和之后的行为空。

例如(行号、内容)

1    
2
3 Hello
4
5 yellow

在这种情况下,如果包含 Hello 的行之前和之后的行是空的(第 2 行和第 4 行),我必须删除从 3 到 1 的行。

我可以使用 tac 和 sed 命令删除从 3 到 1 的行,但是我很难设置 if 条件。

tac file1|sed -e '/Hello/,+3d'|tac

【问题讨论】:

  • 一定要使用sed吗?使用awk 会更容易做到这一点。
  • 你有GNU sed 4.4 吗?新选项 -z 可以提供帮助。
  • @WalterA -z 对此有何帮助?
  • sed '1 N;N;N;N;{s/\n\nHello\n\n/\n/}' file 可能有用(如果你有 GNU sed)。
  • StackOverflow 不是免费的编码服务。你应该try to solve the problem first。请更新您的问题以在minimal reproducible example 中显示您已经尝试过的内容。如需更多信息,请参阅How to Ask,并拨打tour :)

标签: bash shell sed


【解决方案1】:

这可能对你有用(GNU sed):

 sed ':a;N;s/\n/&/3;Ta;/\n\n.*Hello.*\n$/s/.*\n//;ta;P;D' file      

在模式空间中收集 4 行,如果第 2 行和第 4 行为空且第 3 行包含Hello,则删除前三行并重复。否则打印第一行并重复。

【讨论】:

  • :a;ta; - 那是t a 在做什么吗?这看起来几乎像无限循环。
  • @KamilCuk 啊!这是我的测试留下的一点点杂物。顺便说一句,它只是在发生替换时将t 标志设置为true。我注意到,当使用D 命令时,标志不会在循环开始时重置,因此在测试前使用它们时使用皮带和大括号。在这种情况下,ta 命令无论如何都会重置标志,并允许模式空间中的剩余行包含在下一个循环中。
【解决方案2】:

如果您对awk 没问题,请尝试关注。

awk -v string="Hello" '
FNR==NR{
  a[FNR]=$0
  next
}
($0==string) && a[FNR-1]=="" && a[FNR+1]==""{
  a[FNR-1]=a[FNR]=a[FNR-2]="del_flag"
}
END{
  for(i=1;i<=length(a);i++){
    if(a[i]!="del_flag"){
      print a[i]
    }
  }
}
'  Input_file  Input_file

【讨论】:

  • 对于printf "%s\n" "one" "two" "" "Hello" "" "Hello" "" "yellow" 之类的输入文件(hello 的两行和一个重叠的空行)两个Hello 都将被删除。规格不清楚,可能比两个sed 解决方案更好,也可能更差。
  • @WalterA,我考虑了来自 OP 的样本并创建了这个,我现在在驾驶室所以无法测试您提供的样本,将在家里检查一次,但不确定 OP 的 Input_file 是否相同与否。
【解决方案3】:

使用 GNU sed 选项 -z 你可以匹配

some_line
empty line
line With Hello
empty line

并将其替换为空行。

sed -rz 's/(^|\n)[^\n]*\n\nHello\n\n/\1\n/g' file1

编辑:为多个段添加了g

【讨论】:

  • 我找到的文档说-z 用于使用空字节作为行分隔符,而不是换行符。它与空行无关。
  • @Barmar 使用-z,您可以将2 个空行与(^|\n)\n\n 匹配。没有-z sed 是面向行的(将一个空行与^$ 匹配,并且您需要高级@potong 魔法来连续两个空行)。
  • 我明白了,您只是将整个输入视为一行,因为任何地方都没有空字节。你不需要g修饰符来匹配多次吗?
猜你喜欢
  • 2015-06-12
  • 1970-01-01
  • 1970-01-01
  • 2015-06-05
  • 1970-01-01
  • 2014-09-22
  • 1970-01-01
  • 2017-08-19
相关资源
最近更新 更多