使用sed删除两个匹配模式之间的所有行

时间:2011-06-09 03:19:09

标签: regex sed

我有一个类似的文件:

# ID 1
blah blah
blah blah
$ description 1
blah blah
# ID 2
blah
$ description 2
blah blah
blah blah

如何使用sed命令删除#$行之间的所有行?结果将变为:

# ID 1
$ description 1
blah blah
# ID 2
$ description 2
blah blah
blah blah

您能否请您解释一下?

6 个答案:

答案 0 :(得分:47)

使用此sed命令实现:

sed '/^#/,/^\$/{/^#/!{/^\$/!d}}' file.txt

Mac用户(防止extra characters at the end of d command错误)需要在结束括号前添加分号

sed '/^#/,/^\$/{/^#/!{/^\$/!d;};}' file.txt

输出

# ID 1
$ description 1
blah blah
# ID 2
$ description 2
blah blah
blah blah

说明:

  • /^#/,/^\$/会将以#开头的行与以$开头的行之间的所有文字进行匹配。 ^用于行首角色。 $是一个特殊字符,因此需要进行转义。
  • /^#/!表示如果行的开头不是#
  • ,请执行以下操作
  • /^$/!表示如果行的开头不是$
  • ,请执行以下操作
  • d表示删除

总体而言,它首先匹配^#^\$的所有行,然后匹配那些找到不匹配的行 ^#和< strong>不匹配 ^\$并使用d删除它们。

答案 1 :(得分:32)

$ cat test
1
start
2
end
3
$ sed -n '1,/start/p;/end/,$p' test
1
start
end
3
$ sed '/start/,/end/d' test
1
3

答案 2 :(得分:5)

sed的另一种方法:

sed '/^#/,/^\$/{//!d;};' file
  • /^#/,/^\$/:从#开始到从$开始的下一行
  • //!d:删除除地址模式匹配的所有行

答案 3 :(得分:5)

一般来说,如果您的文件内容为 abcde ,其中 a 部分位于模式 b 之前,则部分 c 在模式 d 之前,然后是 e 部分,然后应用以下sed命令,您将得到以下结果。

在此演示中,输出由=> abcde表示,其中字母显示输出中的哪些部分。因此,ae仅显示 a e 部分的输出,ace将是部分 a c e

请注意,如果输出中出现bd,则会出现这些模式(即,它们被视为输出中的部分)。

另外,请勿将/d/模式与命令d混淆。在这些演示中,命令始终处于最后。模式总是在//之间。

  • sed -n -e '/b/,/d/!p' abcde =&gt; AE
  • sed -n -e '/b/,/d/p' abcde =&gt; BCD
  • sed -n -e '/b/,/d/{//!p}' abcde =&gt; ç
  • sed -n -e '/b/,/d/{//p}' abcde =&gt; BD
  • sed -e '/b/,/d/!d' abcde =&gt; BCD
  • sed -e '/b/,/d/d' abcde =&gt; AE
  • sed -e '/b/,/d/{//!d}' abcde =&gt; ABDE
  • sed -e '/b/,/d/{//d}' abcde =&gt;王牌

答案 4 :(得分:3)

我很久以前做过这样的事情,就像是:

sed -n -e "1,/# ID 1/ p" -e "/\$ description 1/,$ p"

类似于:

  • -n取消所有输出
  • -e "1,/# ID 1/ p"从第一行执行,直到您的模式和p(打印)
  • -e "/\$ description 1/,$ p"从第二个模式执行直到结束并执行p(打印)。

我可能错了一些字符串上的转义,所以请仔细检查。

答案 5 :(得分:0)

下面的示例删除了 “ if” “ end if” 之间的行。

将扫描所有文件,并删除两个匹配模式之间的行(包括它们)。

IFS='
'
PATTERN_1="^if"
PATTERN_2="end if"

# Search for the 1st pattern in all files under the current directory.
GREP_RESULTS=(`grep -nRi "$PATTERN_1" .`)

# Go through each result
for line in "${GREP_RESULTS[@]}"; do

   # Save the file and line number where the match was found.
   FILE=${line%%:*}
   START_LINE=`echo "$line" | cut -f2 -d:`

   # Search on the same file for a match of the 2nd pattern. The search 
   # starts from the line where the 1st pattern was matched.
   GREP_RESULT=(`tail -n +${START_LINE} $FILE | grep -in "$PATTERN_2" | head -n1`)
   END_LINE="$(( $START_LINE + `echo "$GREP_RESULT" | cut -f1 -d:` - 1 ))"

   # Remove lines between first and second match from file
   sed -e "${START_LINE},${END_LINE}d;" $FILE > $FILE

done