可以使用Sed实现此过滤器吗?

时间:2017-08-01 03:13:00

标签: awk sed

我写了一个脚本来修饰我的.bash_history文件,过滤"无趣的"来自持久历史记录的ls命令。

(我知道那里有HISTIGNORE变量,但是这也会从当前会话的内存历史记录中排除这些命令。我觉得在范围内包含它们很有用一个会话,但不会在会话中持续存在。)

历史记录文件可以包含带有嵌入换行符的多行历史记录条目,因此条目以时间戳分隔。该脚本采用如下输入文件:

#1501304269
git stash
#1501304270
ls
#1501304318
ls | while IFS= read line; do
echo 'line is: ' $line
done

并过滤掉单行lsmancat命令,生成:

#1501304269
git stash
#1501304318
ls | while IFS= read line; do
echo 'line is: ' $line
done

请注意,多行条目是未过滤的 - 我认为如果它们足够有趣以保证多行,那么它们值得记住。

我在Awk中实现了它,但我一直在阅读Sed的多线功能(NhHx,等等)我想为此目的而尝试。如果不出意外,我很想将两者比作速度。

这是Awk脚本:

/^#[[:digit:]]{10}$/ {
  timestamp = $0
  histentry = ""
  next
}
$1 ~ /^(ls?|man|cat)$/ {
  if (! timestamp) {
    print
  } else {
    histentry = $0
  }
  next
}
timestamp {
  print timestamp
  timestamp = ""
}
histentry {
  print histentry
  histentry = ""
}
{ print }

可以使用Sed完成吗?

1 个答案:

答案 0 :(得分:1)

当然可以用sed完成。下面是一个使用GNU seds -z选项的示例,它允许我们一次处理整个文件而不是行的工作行:

 sed -rz "s/(#[0-9]{10}\n(cat|ls|man)\n)+(#[0-9]{10}\n|$)/\3/g;" yourfile

如果一切正常并且您有历史文件的备份,您甚至可以使用GNU sed -i选项进行就地修改。

-r选项启用扩展的正则表达式,-z选项在手册中解释如下:

  

将输入视为一组行,每行以零字节结束        (ASCII'NUL'字符)而不是换行符。这个选项可以        与'sort -z'和'find -print0'之类的命令一起使用来处理        任意文件名。

基本思路是这样的:一个无趣的命令前面跟着一个时间戳(或者它是文件中的最后一行)。

  • 时间戳RE #[0-9]{10}取自您的awk脚本
  • (#[0-9]{10}\n(cat|ls|man)\n)+匹配一个或多个无趣的命令
  • (#[0-9]{10}|$)第二个时间戳被捕获到\3(由于位于第三对parens中),以便在替换部分中重复使用,并且替换|$符合文件末尾的情况