如何从 BASH 中的历史命令中删除包含特定字符串的所有条目?

如何从 BASH 中的历史命令中删除包含特定字符串的所有条目?

有没有任何命令或方法可以从 bash shell 的历史记录中删除包含特定字符串的所有条目?这对于删除历史记录中包含密码的命令很有用。我知道我们可以通过编号删除每个历史记录条目,但问题是它一次只能删除一个条目,而我每次都需要取出编号来删除新条目。

例如。历史命令显示 5 个包含密码 abcabc 的条目,我想从包含字符串 abcabc 的历史命令中删除所有条目

975  2019-03-15 11:20:30 ll
  976  2019-03-15 11:20:33 ll cd
  977  2019-03-15 11:20:36 ll CD
  978  2019-03-15 11:20:45 chown test1:test1 CD
  979  2019-03-15 11:20:53 chown test1:test1 ./CD
  980  2019-03-15 11:20:57 chown test1:test1 .\CD
  981  2019-03-15 11:22:04 cd /tmp/logs/
  982  2019-06-07 10:36:33 su test1
  983  2019-08-22 08:35:10 su user1
  984  2019-08-22 08:35:15 /opt/abc/legacy.exe -password abcabc
  985  2019-09-24 07:20:45 cd /opt/test1/v6r2017x
  986  2019-09-24 07:20:46 ll
  987  2019-09-24 07:21:18 cd /tmp/
  988  2019-09-24 07:21:19 ll
  989  2019-09-24 07:21:24 cd linux_a64/
  990  2019-09-24 07:21:25 /opt/abc/legacy.exe -password abcabc
  991  2019-09-24 07:24:03 cd  build/
  992  2019-09-24 07:24:04 ll
  993  2019-09-24 07:24:07 cd ..
  994  2019-09-24 07:24:10 /opt/abc/legacy.exe -password abcabc
  995  2019-09-24 07:24:15 cd someapp/bin
  996  2019-09-24 07:24:21 ll
  997  2019-09-24 07:24:33 cd .
  998  2019-09-24 07:24:35 cd ..
  999  2019-09-24 07:24:36 ll

尝试了以下命令,但出现错误,如下所示

servername:~ # sed -i 'g/abcabc/d' /home/user1/.bash_history
sed: -e expression #1, char 2: extra characters after command

预期:没有错误,并且所有包含字符串 abcabc 的条目都应被删除。

答案1

另一个类似于@cprn的答案,但使用awk(而不是cut)和一个函数:

function del_word_history () {
  if [ -z "${1}" ]; then return false; fi
  mapfile -t result <<< "$(history | grep "${1}" | tac | awk '{print $1}')"
  for idx in "${result[@]}"; do
    history -d $idx
  done
}
  • tac反转输出的行(一些帖子指出这并不适用于所有系统)
  • [-z $1 ]true如果传递给函数 ( $1) 的第一个参数为空。
  • mapfile -t手册页;一些指南): 读stdin入数组变量 ( result)
    • "${result[@]}"返回数组
  • awk '{print $1}'GNU 用户指南,简要指南,手册页):用于两者:识别匹配并处理它。它将由空格(默认)分隔的数据分割并将其存储在$n变量中。
  • '{pring $1}'读取为print对第一个单词执行操作

用法:

del_word_history history
del_word_history abcabc
history -w

下面是一个更清洁的解决方案检查我们是否获得了idx的编号history,而不是多行条目的其他单词:

function del_word_history () {
  if [ -z "${1}" ]; then return false; fi
  mapfile -t lines <<< "$(history | grep "${1}" | tac)"
  for line in "${lines[@]}"; do
    idx="$(printf '%s' "${line}" | awk '{ if ($1 ~ /^[0-9]+$/) { print $1 } }')"
    if [ -n "${idx}" ]; then
      echo "removing line ${idx}"
      history -d $idx
    fi
  done
}

主要区别是:

  • lines我们通过以下方式获取数组变量中的完整行mapfile
  • awk '{ if ($1 ~ /^[0-9]+$/) { print $1 }}'检查每行的第一个单词是否是一个数字,并且它stdout是相同的第一个单词(并获取变量idx
  • [ -n ${idx}" ] just checks ifidx` 不为空

答案2

我知道它很旧,但我只是像这样循环执行:

for ln in $( history | grep my_phrase | cut -f2 -d' '); do
    history -d $ln
done
  • $(...)- 命令替换,stdout返回...
  • cut -f2 -d' '- 剪切第二列空格分隔的输出,即行号
  • history -d $ln- 从历史记录中删除给定的行号

一张衬垫,方便复制和粘贴:

for ln in $( history | grep my_phrase | cut -f2 -d' '); do history -d $ln; done

答案3

您可以使用sed从 中删除条目.bash_history
但由于它是一个密码,以避免在 CLI 中再次输入密码,我建议您编辑文件.bashrc并确保将行HISTCONTROL设置为ignorebothor ignorespace。这将允许您输入命令,bash并且如果它们以空格开头,则不会将它们放入历史记录中:

promtpt:$ sed -i '/abcabc/d' /home/user/.bash_history

$请注意和 命令之间的空格,这将使该行在 bash 历史记录中被忽略。

-i: 表示内联编辑文件。
d最后意味着删除包含之间表达式的行/

该解决方案仅适用于 Linux GNU sed

相关内容