有没有任何命令或方法可以从 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 if
idx` 不为空
答案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
设置为ignoreboth
or ignorespace
。这将允许您输入命令,bash
并且如果它们以空格开头,则不会将它们放入历史记录中:
promtpt:$ sed -i '/abcabc/d' /home/user/.bash_history
$
请注意和 命令之间的空格,这将使该行在 bash 历史记录中被忽略。
-i
: 表示内联编辑文件。
d
最后意味着删除包含之间表达式的行/
。
该解决方案仅适用于 Linux GNU sed
。