【问题标题】:Remove the range of lines from file using shell script使用 shell 脚本从文件中删除行范围
【发布时间】:2017-07-09 07:16:37
【问题描述】:

我的测试文件 test.txt 如下:

destination mailerr  { file("/var/log/mail.err" fsync(yes)); };
log { source(src); filter(f_mailerr);  destination(mailerr); };

#
# and also all in one file:
#
destination mail { file("/var/log/mail"); };
log { source(src); filter(f_mail); destination(mail); };

destination mailwarn { file("/var/log/mail.warn"); };
log 
{ 
#source(src); 
filter(f_mailwarn); destination(mailwarn); };

我想使用 shell 脚本删除下面的行

log 
{ 
#source(src); 
filter(f_mailwarn); destination(mailwarn); };

这行可能是不同的结构,比如

log{ source(src); filter(f_mailwarn); destination(mailwarn); };
                          (or)
log
{ 
source(src); 
filter(f_mailwarn); 
destination(mailwarn); 
};
                           (or)
log
{ source(src); filter(f_mailwarn); destination(mailwarn); };
                           (or)
#   log { source(src); filter(f_mailwarn); destination(mailwarn); };
};

这些是可能性。我正在使用 sed 命令:

sed '/log/{:a;/destination(mailwarn);.*}/d;N;ba}' test.txt

但它会删除所有行,因为第一行它自己“日志”来了。这个文件中有很多“日志”,所以如何使用 shell 脚本删除特定的行。

【问题讨论】:

  • 我认为这个问题需要澄清一下。您是否只是尝试根据要删除的行列表从文件中删除行,您是否尝试删除整个 log 函数,或者您是否尝试做其他我不理解的事情?
  • @Jeffrey Cash 我想删除包含“destination(mailwarn);”的日志功能

标签: shell awk sed grep


【解决方案1】:

你可以试试这个sed:

sed  '/^[# ]*log/{:loop; /destination(.*}/d; /}/{n}; N; b loop;}' file

说明:

  • /^[# ]*log/ - 当regex 匹配时开始处理块{}
  • /destination(.*}/d - 当regex 匹配时删除模式空间。开始新的循环。
  • /}/{n} - 当它找到 } 时,打印模式空间并读取下一行输入。 (用于打印非 log...destination() 行。
  • N - 这会将下一行输入附加到模式空间。
  • b loop - 这会将流量控制转移到 loop

【讨论】:

  • 你能补充一点解释吗?真的很想理解这一点并投票赞成:)
  • 这似乎对我不起作用。它删除了所有 log 函数,而不仅仅是 destination(mailwarn)
【解决方案2】:

如果文件不是太大,请使用-z 选项一次性处理整个文件(@SLePort 注意这是一个 GNU 特定选项)

sed -z 's/log[ \t\n]*{[^}]*destination(mailwarn);[ \t\n]*};//g' test.txt
  • log比赛开始
  • [ \t\n]*{ 零个或多个非空格/制表符/换行符后跟{
    • 如果使用[^{]*{ 来避免错误匹配log/mail.warn"); };
  • [^}]* 零个或多个非 } 字符
  • destination(mailwarn); 要匹配的字符串
  • [ \t\n]*}; 零个或多个非空格/制表符/换行符后跟};
  • 匹配的模式被删除,因为替换字符串为空


类似于perl

perl -0777 -pe 's/log\s*\{[^}]*destination\(mailwarn\);\s*};//g' test.txt

【讨论】:

  • 值得一提的是-z是一个GNU sed标志。
  • 善用sed++的GNU特性
【解决方案3】:

这是我完成工作的有点笨拙的方法。它似乎适用于您发布的所有情况,但绝不是解决此问题的通用方法。

tr '\n' '\0' < test.txt | sed 's/log[^{}]*{[^}]*destination(mailwarn);[^}]*};//g' | tr '\0' '\n'

如果test.txt 包含空字符,它可能无法正常工作。该命令本质上是查找log,然后是{,然后直到} 到达destination(mailwarn);,最后是};,如果找到则删除此匹配项。

我希望其他人针对这个问题发布更强大的解决方案,但这是我能够想出的唯一快速解决方案。

【讨论】:

    【解决方案4】:

    使用 sed:

    sed '/^#*[[:blank:]]*log/{:a;/};/!{N;ba;s/\n//;};/destination(mailwarn)/d;}' file
    

    log}; 的行添加到模式空间,在其中搜索destination(mailwarn),如果找到,则删除行。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2017-01-25
      • 2015-08-01
      • 1970-01-01
      • 1970-01-01
      • 2022-10-23
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多